#include "system/filesys.h"
#include "system/locale.h"
#include "system/shmem.h"
+#include "system/passwd.h"
#undef malloc
#undef strcasecmp
#undef strncasecmp
#undef strdup
#undef realloc
-
-#if defined(UID_WRAPPER)
-#if !defined(UID_WRAPPER_REPLACE) && !defined(UID_WRAPPER_NOT_REPLACE)
-#define UID_WRAPPER_REPLACE
-#include "../uid_wrapper/uid_wrapper.h"
-#endif
-#else
-#define uwrap_enabled() 0
-#endif
+#undef calloc
/**
* @file
{
char *fname;
int fd;
+ mode_t mask;
if (!dir) {
dir = tmpdir();
errno = ENOMEM;
return -1;
}
+ mask = umask(S_IRWXO | S_IRWXG);
fd = mkstemp(fname);
+ umask(mask);
if (fd == -1) {
TALLOC_FREE(fname);
return -1;
return(st.st_mtime);
}
+/**
+ Check file permissions.
+**/
+
+_PUBLIC_ bool file_check_permissions(const char *fname,
+ uid_t uid,
+ mode_t file_perms,
+ struct stat *pst)
+{
+ int ret;
+ struct stat st;
+
+ if (pst == NULL) {
+ pst = &st;
+ }
+
+ ZERO_STRUCTP(pst);
+
+ ret = stat(fname, pst);
+ if (ret != 0) {
+ DEBUG(0, ("stat failed on file '%s': %s\n",
+ fname, strerror(errno)));
+ return false;
+ }
+
+ if (pst->st_uid != uid && !uid_wrapper_enabled()) {
+ DEBUG(0, ("invalid ownership of file '%s': "
+ "owned by uid %u, should be %u\n",
+ fname, (unsigned int)pst->st_uid,
+ (unsigned int)uid));
+ return false;
+ }
+
+ if ((pst->st_mode & 0777) != file_perms) {
+ DEBUG(0, ("invalid permissions on file "
+ "'%s': has 0%o should be 0%o\n", fname,
+ (unsigned int)(pst->st_mode & 0777),
+ (unsigned int)file_perms));
+ return false;
+ }
+
+ return true;
+}
+
/**
Check if a directory exists.
**/
/**
* Try to create the specified directory if it didn't exist.
*
- * @retval true if the directory already existed and has the right permissions
+ * @retval true if the directory already existed
* or was successfully created.
*/
-_PUBLIC_ bool directory_create_or_exist(const char *dname, uid_t uid,
- mode_t dir_perms)
+_PUBLIC_ bool directory_create_or_exist(const char *dname,
+ mode_t dir_perms)
{
+ int ret;
+ struct stat st;
mode_t old_umask;
- struct stat st;
-
+
+ ret = lstat(dname, &st);
+ if (ret == 0) {
+ return true;
+ }
+
+ if (errno != ENOENT) {
+ DEBUG(0, ("lstat failed on directory %s: %s\n",
+ dname, strerror(errno)));
+ return false;
+ }
+
+ /* Create directory */
old_umask = umask(0);
- if (lstat(dname, &st) == -1) {
- if (errno == ENOENT) {
- /* Create directory */
- if (mkdir(dname, dir_perms) == -1) {
- DEBUG(0, ("error creating directory "
- "%s: %s\n", dname,
- strerror(errno)));
- umask(old_umask);
- return false;
- }
- } else {
- DEBUG(0, ("lstat failed on directory %s: %s\n",
- dname, strerror(errno)));
- umask(old_umask);
- return false;
- }
- } else {
- /* Check ownership and permission on existing directory */
- if (!S_ISDIR(st.st_mode)) {
- DEBUG(0, ("directory %s isn't a directory\n",
- dname));
- umask(old_umask);
- return false;
- }
- if (st.st_uid != uid && !uwrap_enabled()) {
- DEBUG(0, ("invalid ownership on directory "
- "%s\n", dname));
- umask(old_umask);
- return false;
- }
- if ((st.st_mode & 0777) != dir_perms) {
- DEBUG(0, ("invalid permissions on directory "
- "'%s': has 0%o should be 0%o\n", dname,
- (st.st_mode & 0777), dir_perms));
- umask(old_umask);
- return false;
- }
+ ret = mkdir(dname, dir_perms);
+ if (ret == -1 && errno != EEXIST) {
+ DEBUG(0, ("mkdir failed on directory "
+ "%s: %s\n", dname,
+ strerror(errno)));
+ umask(old_umask);
+ return false;
+ }
+ umask(old_umask);
+
+ ret = lstat(dname, &st);
+ if (ret == -1) {
+ DEBUG(0, ("lstat failed on created directory %s: %s\n",
+ dname, strerror(errno)));
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * @brief Try to create a specified directory if it doesn't exist.
+ *
+ * The function creates a directory with the given uid and permissions if it
+ * doesn't exist. If it exists it makes sure the uid and permissions are
+ * correct and it will fail if they are different.
+ *
+ * @param[in] dname The directory to create.
+ *
+ * @param[in] uid The uid the directory needs to belong too.
+ *
+ * @param[in] dir_perms The expected permissions of the directory.
+ *
+ * @return True on success, false on error.
+ */
+_PUBLIC_ bool directory_create_or_exist_strict(const char *dname,
+ uid_t uid,
+ mode_t dir_perms)
+{
+ struct stat st;
+ bool ok;
+ int rc;
+
+ ok = directory_create_or_exist(dname, dir_perms);
+ if (!ok) {
+ return false;
+ }
+
+ rc = lstat(dname, &st);
+ if (rc == -1) {
+ DEBUG(0, ("lstat failed on created directory %s: %s\n",
+ dname, strerror(errno)));
+ return false;
+ }
+
+ /* Check ownership and permission on existing directory */
+ if (!S_ISDIR(st.st_mode)) {
+ DEBUG(0, ("directory %s isn't a directory\n",
+ dname));
+ return false;
+ }
+ if (st.st_uid != uid && !uid_wrapper_enabled()) {
+ DEBUG(0, ("invalid ownership on directory "
+ "%s\n", dname));
+ return false;
+ }
+ if ((st.st_mode & 0777) != dir_perms) {
+ DEBUG(0, ("invalid permissions on directory "
+ "'%s': has 0%o should be 0%o\n", dname,
+ (unsigned int)(st.st_mode & 0777), (unsigned int)dir_perms));
+ return false;
}
+
return true;
-}
+}
/**
{
/* Doing kill with a non-positive pid causes messages to be
* sent to places we don't want. */
- SMB_ASSERT(pid > 0);
+ if (pid <= 0) {
+ return false;
+ }
return(kill(pid,0) == 0 || errno != ESRCH);
}
return true;
}
+struct debug_channel_level {
+ int channel;
+ int level;
+};
+
+static void debugadd_channel_cb(const char *buf, void *private_data)
+{
+ struct debug_channel_level *dcl =
+ (struct debug_channel_level *)private_data;
+
+ DEBUGADDC(dcl->channel, dcl->level,("%s", buf));
+}
+
static void debugadd_cb(const char *buf, void *private_data)
{
int *plevel = (int *)private_data;
dump_data_cb(buf, len, false, debugadd_cb, &level);
}
+/**
+ * Write dump of binary data to the log file.
+ *
+ * The data is only written if the log level is at least level for
+ * debug class dbgc_class.
+ */
+_PUBLIC_ void dump_data_dbgc(int dbgc_class, int level, const uint8_t *buf, int len)
+{
+ struct debug_channel_level dcl = { dbgc_class, level };
+
+ if (!DEBUGLVLC(dbgc_class, level)) {
+ return;
+ }
+ dump_data_cb(buf, len, false, debugadd_channel_cb, &dcl);
+}
+
/**
* Write dump of binary data to the log file.
*
dump_data_cb(buf, len, true, debugadd_cb, &level);
}
+static void fprintf_cb(const char *buf, void *private_data)
+{
+ FILE *f = (FILE *)private_data;
+ fprintf(f, "%s", buf);
+}
+
+void dump_data_file(const uint8_t *buf, int len, bool omit_zero_bytes,
+ FILE *f)
+{
+ dump_data_cb(buf, len, omit_zero_bytes, fprintf_cb, f);
+}
/**
malloc that aborts with smb_panic on fail or zero size.
Like strdup but for memory.
**/
-_PUBLIC_ void *memdup(const void *p, size_t size)
+_PUBLIC_ void *smb_memdup(const void *p, size_t size)
{
void *p2;
if (size == 0)
return realloc_array(NULL, el_size, count, false);
}
+/****************************************************************************
+ Type-safe memalign
+****************************************************************************/
+
+void *memalign_array(size_t el_size, size_t align, unsigned int count)
+{
+ if (count*el_size >= MAX_MALLOC_SIZE) {
+ return NULL;
+ }
+
+ return memalign(align, el_size*count);
+}
+
+/****************************************************************************
+ Type-safe calloc.
+****************************************************************************/
+
+void *calloc_array(size_t size, size_t nmemb)
+{
+ if (nmemb >= MAX_MALLOC_SIZE/size) {
+ return NULL;
+ }
+ if (size == 0 || nmemb == 0) {
+ return NULL;
+ }
+ return calloc(nmemb, size);
+}
+
/**
Trim the specified elements off the front and back of a string.
**/
* - "0xnn" or "0Xnn" is specially catered for.
* - The first non-hex-digit character (apart from possibly leading "0x"
* finishes the conversion and skips the rest of the input.
+ * - A single hex-digit character at the end of the string is skipped.
*
* valid examples: "0A5D15"; "0x123456"
*/
i += 2; /* skip two chars */
}
- for (; i < strhex_len && strhex[i] != 0; i++) {
+ for (; i+1 < strhex_len && strhex[i] != 0 && strhex[i+1] != 0; i++) {
p1 = strchr(hexchars, toupper((unsigned char)strhex[i]));
if (p1 == NULL) {
break;
return ret_blob;
}
+/**
+ * Print a buf in hex. Assumes dst is at least (srclen*2)+1 large.
+ */
+_PUBLIC_ void hex_encode_buf(char *dst, const uint8_t *src, size_t srclen)
+{
+ size_t i;
+ for (i=0; i<srclen; i++) {
+ snprintf(dst + i*2, 3, "%02X", src[i]);
+ }
+ /*
+ * Ensure 0-termination for 0-length buffers
+ */
+ dst[srclen*2] = '\0';
+}
/**
* Routine to print a buffer as HEX digits, into an allocated string.
*/
_PUBLIC_ void hex_encode(const unsigned char *buff_in, size_t len, char **out_hex_buffer)
{
- int i;
char *hex_buffer;
*out_hex_buffer = malloc_array_p(char, (len*2)+1);
hex_buffer = *out_hex_buffer;
-
- for (i = 0; i < len; i++)
- slprintf(&hex_buffer[i*2], 3, "%02X", buff_in[i]);
+ hex_encode_buf(hex_buffer, buff_in, len);
}
/**
*/
_PUBLIC_ char *hex_encode_talloc(TALLOC_CTX *mem_ctx, const unsigned char *buff_in, size_t len)
{
- int i;
char *hex_buffer;
hex_buffer = talloc_array(mem_ctx, char, (len*2)+1);
if (!hex_buffer) {
return NULL;
}
-
- for (i = 0; i < len; i++)
- slprintf(&hex_buffer[i*2], 3, "%02X", buff_in[i]);
-
+ hex_encode_buf(hex_buffer, buff_in, len);
talloc_set_name_const(hex_buffer, hex_buffer);
return hex_buffer;
}
buf = mmap(NULL, bufsz, PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED,
-1 /* fd */, 0 /* offset */);
#else
+{
+ int saved_errno;
+ int fd;
+
+ fd = open("/dev/zero", O_RDWR);
+ if (fd == -1) {
+ return NULL;
+ }
+
buf = mmap(NULL, bufsz, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED,
- open("/dev/zero", O_RDWR), 0 /* offset */);
+ fd, 0 /* offset */);
+ saved_errno = errno;
+ close(fd);
+ errno = saved_errno;
+}
#endif
if (buf == MAP_FAILED) {