/*
* Unix SMB/CIFS implementation.
* store smbd profiling information in shared memory
* Copyright (C) Andrew Tridgell 1999
* Copyright (C) James Peach 2006
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "replace.h"
#include
#include
#include
#include "lib/crypto/gnutls_helpers.h"
#include "lib/util/byteorder.h"
#include "source3/include/smbprofile.h"
void smbprofile_stats_accumulate(struct profile_stats *acc,
const struct profile_stats *add)
{
#define SMBPROFILE_STATS_START
#define SMBPROFILE_STATS_SECTION_START(name, display)
#define SMBPROFILE_STATS_COUNT(name) \
do { \
acc->values.name##_stats.count += \
add->values.name##_stats.count; \
} while (0);
#define SMBPROFILE_STATS_TIME(name) \
do { \
acc->values.name##_stats.time += \
add->values.name##_stats.time; \
} while (0);
#define SMBPROFILE_STATS_BASIC(name) \
do { \
acc->values.name##_stats.count += \
add->values.name##_stats.count; \
acc->values.name##_stats.time += \
add->values.name##_stats.time; \
} while (0);
#define SMBPROFILE_STATS_BYTES(name) \
do { \
acc->values.name##_stats.count += \
add->values.name##_stats.count; \
acc->values.name##_stats.time += \
add->values.name##_stats.time; \
acc->values.name##_stats.idle += \
add->values.name##_stats.idle; \
acc->values.name##_stats.bytes += \
add->values.name##_stats.bytes; \
} while (0);
#define SMBPROFILE_STATS_IOBYTES(name) \
do { \
acc->values.name##_stats.count += \
add->values.name##_stats.count; \
acc->values.name##_stats.time += \
add->values.name##_stats.time; \
acc->values.name##_stats.idle += \
add->values.name##_stats.idle; \
acc->values.name##_stats.inbytes += \
add->values.name##_stats.inbytes; \
acc->values.name##_stats.outbytes += \
add->values.name##_stats.outbytes; \
} while (0);
#define SMBPROFILE_STATS_SECTION_END
#define SMBPROFILE_STATS_END
SMBPROFILE_STATS_ALL_SECTIONS
#undef SMBPROFILE_STATS_START
#undef SMBPROFILE_STATS_SECTION_START
#undef SMBPROFILE_STATS_COUNT
#undef SMBPROFILE_STATS_TIME
#undef SMBPROFILE_STATS_BASIC
#undef SMBPROFILE_STATS_BYTES
#undef SMBPROFILE_STATS_IOBYTES
#undef SMBPROFILE_STATS_SECTION_END
#undef SMBPROFILE_STATS_END
}
int smbprofile_magic(const struct profile_stats *stats, uint64_t *_magic)
{
uint8_t digest[gnutls_hash_get_len(GNUTLS_DIG_SHA1)];
gnutls_hash_hd_t hash_hnd = NULL;
int rc;
GNUTLS_FIPS140_SET_LAX_MODE();
rc = gnutls_hash_init(&hash_hnd, GNUTLS_DIG_SHA1);
if (rc < 0) {
goto out;
}
rc = gnutls_hash(hash_hnd, stats, sizeof(*stats));
#define __UPDATE(str) \
do { \
rc |= gnutls_hash(hash_hnd, str, strlen(str)); \
} while (0)
#define SMBPROFILE_STATS_START
#define SMBPROFILE_STATS_SECTION_START(name, display) \
do { \
__UPDATE(#name "+" #display); \
} while (0);
#define SMBPROFILE_STATS_COUNT(name) \
do { \
__UPDATE(#name "+count"); \
} while (0);
#define SMBPROFILE_STATS_TIME(name) \
do { \
__UPDATE(#name "+time"); \
} while (0);
#define SMBPROFILE_STATS_BASIC(name) \
do { \
__UPDATE(#name "+count"); \
__UPDATE(#name "+time"); \
} while (0);
#define SMBPROFILE_STATS_BYTES(name) \
do { \
__UPDATE(#name "+count"); \
__UPDATE(#name "+time"); \
__UPDATE(#name "+idle"); \
__UPDATE(#name "+bytes"); \
} while (0);
#define SMBPROFILE_STATS_IOBYTES(name) \
do { \
__UPDATE(#name "+count"); \
__UPDATE(#name "+time"); \
__UPDATE(#name "+idle"); \
__UPDATE(#name "+inbytes"); \
__UPDATE(#name "+outbytes"); \
} while (0);
#define SMBPROFILE_STATS_SECTION_END
#define SMBPROFILE_STATS_END
SMBPROFILE_STATS_ALL_SECTIONS
#undef __UPDATE
#undef SMBPROFILE_STATS_START
#undef SMBPROFILE_STATS_SECTION_START
#undef SMBPROFILE_STATS_COUNT
#undef SMBPROFILE_STATS_TIME
#undef SMBPROFILE_STATS_BASIC
#undef SMBPROFILE_STATS_BYTES
#undef SMBPROFILE_STATS_IOBYTES
#undef SMBPROFILE_STATS_SECTION_END
#undef SMBPROFILE_STATS_END
if (rc != 0) {
gnutls_hash_deinit(hash_hnd, NULL);
goto out;
}
gnutls_hash_deinit(hash_hnd, digest);
out:
GNUTLS_FIPS140_SET_STRICT_MODE();
if (rc == 0) {
uint64_t magic = PULL_LE_U64(digest, 0);
if (magic == 0) {
magic = PULL_LE_U64(digest, 0);
}
*_magic = magic;
}
return rc;
}
static int smbprofile_collect_fn(struct tdb_context *tdb,
TDB_DATA key,
TDB_DATA value,
void *private_data)
{
struct profile_stats *acc = (struct profile_stats *)private_data;
const struct profile_stats *v;
if (value.dsize != sizeof(struct profile_stats)) {
return 0;
}
v = (const struct profile_stats *)value.dptr;
if (v->magic != acc->magic) {
return 0;
}
smbprofile_stats_accumulate(acc, v);
return 0;
}
void smbprofile_collect_tdb(struct tdb_context *tdb,
uint64_t magic,
struct profile_stats *stats)
{
*stats = (struct profile_stats){.magic = magic};
tdb_traverse_read(tdb, smbprofile_collect_fn, stats);
}