mirror of
https://gitlab.gnome.org/GNOME/libsecret.git
synced 2024-12-22 04:38:55 +00:00
pam: port PAM module egg helper functions from gnome-keyring
This change is a part of the port PAM module from gnome-keyring patch set. These changes port gnome-keyring/egg/egg-unix-credentials.c to libsecret/egg Furthermore ports gnome-keyring/egg/egg-buffer.c to libsecret/egg Signed-off-by: Dhanuka Warusadura <dhanuka@gnome.org>
This commit is contained in:
parent
175514244f
commit
9cfa77f967
581
egg/egg-buffer.c
Normal file
581
egg/egg-buffer.c
Normal file
@ -0,0 +1,581 @@
|
||||
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
|
||||
/* egg-buffer.c - Generic data buffer, used by openssh, gnome-keyring
|
||||
|
||||
Copyright (C) 2007 Stefan Walter
|
||||
|
||||
The Gnome Keyring Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The Gnome Keyring Library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the Gnome Library; see the file COPYING.LIB. If not,
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
Author: Stef Walter <stef@memberwebs.com>
|
||||
*/
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "egg-buffer.h"
|
||||
|
||||
#define DEFAULT_ALLOCATOR ((EggBufferAllocator)realloc)
|
||||
|
||||
int
|
||||
egg_buffer_init (EggBuffer *buffer, size_t reserve)
|
||||
{
|
||||
return egg_buffer_init_full (buffer, reserve, NULL);
|
||||
}
|
||||
|
||||
int
|
||||
egg_buffer_init_full (EggBuffer *buffer, size_t reserve, EggBufferAllocator allocator)
|
||||
{
|
||||
memset (buffer, 0, sizeof (*buffer));
|
||||
|
||||
if (!allocator)
|
||||
allocator = DEFAULT_ALLOCATOR;
|
||||
if (reserve == 0)
|
||||
reserve = 64;
|
||||
|
||||
buffer->buf = (allocator) (NULL, reserve);
|
||||
if (!buffer->buf) {
|
||||
buffer->failures++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
buffer->len = 0;
|
||||
buffer->allocated_len = reserve;
|
||||
buffer->failures = 0;
|
||||
buffer->allocator = allocator;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
egg_buffer_init_static (EggBuffer* buffer, const unsigned char *buf, size_t len)
|
||||
{
|
||||
memset (buffer, 0, sizeof (*buffer));
|
||||
|
||||
buffer->buf = (unsigned char*)buf;
|
||||
buffer->len = len;
|
||||
buffer->allocated_len = len;
|
||||
buffer->failures = 0;
|
||||
|
||||
/* A null allocator, and the buffer can't change in size */
|
||||
buffer->allocator = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
egg_buffer_init_allocated (EggBuffer *buffer, unsigned char *buf, size_t len,
|
||||
EggBufferAllocator allocator)
|
||||
{
|
||||
memset (buffer, 0, sizeof (*buffer));
|
||||
|
||||
if (!allocator)
|
||||
allocator = DEFAULT_ALLOCATOR;
|
||||
|
||||
buffer->buf = buf;
|
||||
buffer->len = len;
|
||||
buffer->allocated_len = len;
|
||||
buffer->failures = 0;
|
||||
buffer->allocator = allocator;
|
||||
}
|
||||
|
||||
void
|
||||
egg_buffer_reset (EggBuffer *buffer)
|
||||
{
|
||||
memset (buffer->buf, 0, buffer->allocated_len);
|
||||
buffer->len = 0;
|
||||
buffer->failures = 0;
|
||||
}
|
||||
|
||||
void
|
||||
egg_buffer_uninit (EggBuffer *buffer)
|
||||
{
|
||||
if (!buffer)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Free the memory block using allocator. If no allocator,
|
||||
* then this memory is ownerd elsewhere and not to be freed.
|
||||
*/
|
||||
if (buffer->buf && buffer->allocator)
|
||||
(buffer->allocator) (buffer->buf, 0);
|
||||
|
||||
memset (buffer, 0, sizeof (*buffer));
|
||||
}
|
||||
|
||||
unsigned char*
|
||||
egg_buffer_uninit_steal (EggBuffer *buffer, size_t *n_result)
|
||||
{
|
||||
unsigned char *result;
|
||||
|
||||
if (n_result)
|
||||
*n_result = buffer->len;
|
||||
result = buffer->buf;
|
||||
|
||||
memset (buffer, 0, sizeof (*buffer));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int
|
||||
egg_buffer_set_allocator (EggBuffer *buffer, EggBufferAllocator allocator)
|
||||
{
|
||||
unsigned char *buf = NULL;
|
||||
|
||||
if (!allocator)
|
||||
allocator = DEFAULT_ALLOCATOR;
|
||||
if (buffer->allocator == allocator)
|
||||
return 1;
|
||||
|
||||
if (buffer->allocated_len) {
|
||||
/* Reallocate memory block using new allocator */
|
||||
buf = (allocator) (NULL, buffer->allocated_len);
|
||||
if (buf == NULL)
|
||||
return 0;
|
||||
|
||||
/* Copy stuff into new memory */
|
||||
memcpy (buf, buffer->buf, buffer->allocated_len);
|
||||
}
|
||||
|
||||
/* If old wasn't static, then free it */
|
||||
if (buffer->allocator && buffer->buf)
|
||||
(buffer->allocator) (buffer->buf, 0);
|
||||
|
||||
buffer->buf = buf;
|
||||
buffer->allocator = allocator;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
egg_buffer_equal (EggBuffer *b1, EggBuffer *b2)
|
||||
{
|
||||
if (b1->len != b2->len)
|
||||
return 0;
|
||||
return memcmp (b1->buf, b2->buf, b1->len) == 0;
|
||||
}
|
||||
|
||||
int
|
||||
egg_buffer_reserve (EggBuffer *buffer, size_t len)
|
||||
{
|
||||
unsigned char *newbuf;
|
||||
size_t newlen;
|
||||
|
||||
if (len < buffer->allocated_len)
|
||||
return 1;
|
||||
|
||||
/* Calculate a new length, minimize number of buffer allocations */
|
||||
newlen = buffer->allocated_len * 2;
|
||||
if (len > newlen)
|
||||
newlen += len;
|
||||
|
||||
/* Memory owned elsewhere can't be reallocated */
|
||||
if (!buffer->allocator) {
|
||||
buffer->failures++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Reallocate built in buffer using allocator */
|
||||
newbuf = (buffer->allocator) (buffer->buf, newlen);
|
||||
if (!newbuf) {
|
||||
buffer->failures++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
buffer->buf = newbuf;
|
||||
buffer->allocated_len = newlen;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
egg_buffer_resize (EggBuffer *buffer, size_t len)
|
||||
{
|
||||
if (!egg_buffer_reserve (buffer, len))
|
||||
return 0;
|
||||
|
||||
buffer->len = len;
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned char*
|
||||
egg_buffer_add_empty (EggBuffer *buffer, size_t len)
|
||||
{
|
||||
size_t pos = buffer->len;
|
||||
if (!egg_buffer_reserve (buffer, buffer->len + len))
|
||||
return NULL;
|
||||
buffer->len += len;
|
||||
return buffer->buf + pos;
|
||||
}
|
||||
|
||||
int
|
||||
egg_buffer_append (EggBuffer *buffer, const unsigned char *val,
|
||||
size_t len)
|
||||
{
|
||||
if (!egg_buffer_reserve (buffer, buffer->len + len))
|
||||
return 0; /* failures already incremented */
|
||||
memcpy (buffer->buf + buffer->len, val, len);
|
||||
buffer->len += len;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
egg_buffer_add_byte (EggBuffer *buffer, unsigned char val)
|
||||
{
|
||||
if (!egg_buffer_reserve (buffer, buffer->len + 1))
|
||||
return 0; /* failures already incremented */
|
||||
buffer->buf[buffer->len] = val;
|
||||
buffer->len++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
egg_buffer_get_byte (EggBuffer *buffer, size_t offset,
|
||||
size_t *next_offset, unsigned char *val)
|
||||
{
|
||||
unsigned char *ptr;
|
||||
if (buffer->len < 1 || offset > buffer->len - 1) {
|
||||
buffer->failures++;
|
||||
return 0;
|
||||
}
|
||||
ptr = (unsigned char*)buffer->buf + offset;
|
||||
if (val != NULL)
|
||||
*val = *ptr;
|
||||
if (next_offset != NULL)
|
||||
*next_offset = offset + 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
egg_buffer_encode_uint16 (unsigned char* buf, uint16_t val)
|
||||
{
|
||||
buf[0] = (val >> 8) & 0xff;
|
||||
buf[1] = (val >> 0) & 0xff;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
egg_buffer_decode_uint16 (unsigned char* buf)
|
||||
{
|
||||
uint16_t val = buf[0] << 8 | buf[1];
|
||||
return val;
|
||||
}
|
||||
|
||||
int
|
||||
egg_buffer_add_uint16 (EggBuffer *buffer, uint16_t val)
|
||||
{
|
||||
if (!egg_buffer_reserve (buffer, buffer->len + 2))
|
||||
return 0; /* failures already incremented */
|
||||
buffer->len += 2;
|
||||
egg_buffer_set_uint16 (buffer, buffer->len - 2, val);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
egg_buffer_set_uint16 (EggBuffer *buffer, size_t offset, uint16_t val)
|
||||
{
|
||||
unsigned char *ptr;
|
||||
if (buffer->len < 2 || offset > buffer->len - 2) {
|
||||
buffer->failures++;
|
||||
return 0;
|
||||
}
|
||||
ptr = (unsigned char*)buffer->buf + offset;
|
||||
egg_buffer_encode_uint16 (ptr, val);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
egg_buffer_get_uint16 (EggBuffer *buffer, size_t offset,
|
||||
size_t *next_offset, uint16_t *val)
|
||||
{
|
||||
unsigned char *ptr;
|
||||
if (buffer->len < 2 || offset > buffer->len - 2) {
|
||||
buffer->failures++;
|
||||
return 0;
|
||||
}
|
||||
ptr = (unsigned char*)buffer->buf + offset;
|
||||
if (val != NULL)
|
||||
*val = egg_buffer_decode_uint16 (ptr);
|
||||
if (next_offset != NULL)
|
||||
*next_offset = offset + 2;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
egg_buffer_encode_uint32 (unsigned char* buf, uint32_t val)
|
||||
{
|
||||
buf[0] = (val >> 24) & 0xff;
|
||||
buf[1] = (val >> 16) & 0xff;
|
||||
buf[2] = (val >> 8) & 0xff;
|
||||
buf[3] = (val >> 0) & 0xff;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
egg_buffer_decode_uint32 (unsigned char* ptr)
|
||||
{
|
||||
uint32_t val = (uint32_t) ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | ptr[3];
|
||||
return val;
|
||||
}
|
||||
|
||||
int
|
||||
egg_buffer_add_uint32 (EggBuffer *buffer, uint32_t val)
|
||||
{
|
||||
if (!egg_buffer_reserve (buffer, buffer->len + 4))
|
||||
return 0; /* failures already incremented */
|
||||
buffer->len += 4;
|
||||
egg_buffer_set_uint32 (buffer, buffer->len - 4, val);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
egg_buffer_set_uint32 (EggBuffer *buffer, size_t offset, uint32_t val)
|
||||
{
|
||||
unsigned char *ptr;
|
||||
if (buffer->len < 4 || offset > buffer->len - 4) {
|
||||
buffer->failures++;
|
||||
return 0;
|
||||
}
|
||||
ptr = (unsigned char*)buffer->buf + offset;
|
||||
egg_buffer_encode_uint32 (ptr, val);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
egg_buffer_get_uint32 (EggBuffer *buffer, size_t offset, size_t *next_offset,
|
||||
uint32_t *val)
|
||||
{
|
||||
unsigned char *ptr;
|
||||
if (buffer->len < 4 || offset > buffer->len - 4) {
|
||||
buffer->failures++;
|
||||
return 0;
|
||||
}
|
||||
ptr = (unsigned char*)buffer->buf + offset;
|
||||
if (val != NULL)
|
||||
*val = egg_buffer_decode_uint32 (ptr);
|
||||
if (next_offset != NULL)
|
||||
*next_offset = offset + 4;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
egg_buffer_add_uint64 (EggBuffer *buffer, uint64_t val)
|
||||
{
|
||||
if (!egg_buffer_add_uint32 (buffer, ((val >> 32) & 0xffffffff)))
|
||||
return 0;
|
||||
return egg_buffer_add_uint32 (buffer, (val & 0xffffffff));
|
||||
}
|
||||
|
||||
int
|
||||
egg_buffer_get_uint64 (EggBuffer *buffer, size_t offset,
|
||||
size_t *next_offset, uint64_t *val)
|
||||
{
|
||||
uint32_t a, b;
|
||||
if (!egg_buffer_get_uint32 (buffer, offset, &offset, &a))
|
||||
return 0;
|
||||
if (!egg_buffer_get_uint32 (buffer, offset, &offset, &b))
|
||||
return 0;
|
||||
if (val != NULL)
|
||||
*val = ((uint64_t)a) << 32 | b;
|
||||
if (next_offset != NULL)
|
||||
*next_offset = offset;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
egg_buffer_add_byte_array (EggBuffer *buffer, const unsigned char *val,
|
||||
size_t len)
|
||||
{
|
||||
if (val == NULL)
|
||||
return egg_buffer_add_uint32 (buffer, 0xffffffff);
|
||||
if (len >= 0x7fffffff) {
|
||||
buffer->failures++;
|
||||
return 0;
|
||||
}
|
||||
if (!egg_buffer_add_uint32 (buffer, len))
|
||||
return 0;
|
||||
return egg_buffer_append (buffer, val, len);
|
||||
}
|
||||
|
||||
unsigned char*
|
||||
egg_buffer_add_byte_array_empty (EggBuffer *buffer, size_t vlen)
|
||||
{
|
||||
if (vlen >= 0x7fffffff) {
|
||||
buffer->failures++;
|
||||
return NULL;
|
||||
}
|
||||
if (!egg_buffer_add_uint32 (buffer, vlen))
|
||||
return NULL;
|
||||
return egg_buffer_add_empty (buffer, vlen);
|
||||
}
|
||||
|
||||
int
|
||||
egg_buffer_get_byte_array (EggBuffer *buffer, size_t offset,
|
||||
size_t *next_offset, const unsigned char **val,
|
||||
size_t *vlen)
|
||||
{
|
||||
uint32_t len;
|
||||
if (!egg_buffer_get_uint32 (buffer, offset, &offset, &len))
|
||||
return 0;
|
||||
if (len == 0xffffffff) {
|
||||
if (next_offset)
|
||||
*next_offset = offset;
|
||||
if (val)
|
||||
*val = NULL;
|
||||
if (vlen)
|
||||
*vlen = 0;
|
||||
return 1;
|
||||
} else if (len >= 0x7fffffff) {
|
||||
buffer->failures++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (buffer->len < len || offset > buffer->len - len) {
|
||||
buffer->failures++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (val)
|
||||
*val = buffer->buf + offset;
|
||||
if (vlen)
|
||||
*vlen = len;
|
||||
if (next_offset)
|
||||
*next_offset = offset + len;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
egg_buffer_add_string (EggBuffer *buffer, const char *str)
|
||||
{
|
||||
if (str == NULL) {
|
||||
return egg_buffer_add_uint32 (buffer, 0xffffffff);
|
||||
} else {
|
||||
size_t len = strlen (str);
|
||||
if (len >= 0x7fffffff)
|
||||
return 0;
|
||||
if (!egg_buffer_add_uint32 (buffer, len))
|
||||
return 0;
|
||||
return egg_buffer_append (buffer, (unsigned char*)str, len);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
egg_buffer_get_string (EggBuffer *buffer, size_t offset, size_t *next_offset,
|
||||
char **str_ret, EggBufferAllocator allocator)
|
||||
{
|
||||
uint32_t len;
|
||||
|
||||
if (!allocator)
|
||||
allocator = buffer->allocator;
|
||||
if (!allocator)
|
||||
allocator = DEFAULT_ALLOCATOR;
|
||||
|
||||
if (!egg_buffer_get_uint32 (buffer, offset, &offset, &len)) {
|
||||
return 0;
|
||||
}
|
||||
if (len == 0xffffffff) {
|
||||
*next_offset = offset;
|
||||
*str_ret = NULL;
|
||||
return 1;
|
||||
} else if (len >= 0x7fffffff) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (buffer->len < len ||
|
||||
offset > buffer->len - len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Make sure no null characters in string */
|
||||
if (memchr (buffer->buf + offset, 0, len) != NULL)
|
||||
return 0;
|
||||
|
||||
/* The passed allocator may be for non-pageable memory */
|
||||
*str_ret = (allocator) (NULL, len + 1);
|
||||
if (!*str_ret)
|
||||
return 0;
|
||||
memcpy (*str_ret, buffer->buf + offset, len);
|
||||
|
||||
/* Always zero terminate */
|
||||
(*str_ret)[len] = 0;
|
||||
*next_offset = offset + len;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
egg_buffer_add_stringv (EggBuffer *buffer, const char** strv)
|
||||
{
|
||||
const char **v;
|
||||
uint32_t n = 0;
|
||||
|
||||
if (!strv)
|
||||
return 0;
|
||||
|
||||
/* Add the number of strings coming */
|
||||
for (v = strv; *v; ++v)
|
||||
++n;
|
||||
if (!egg_buffer_add_uint32 (buffer, n))
|
||||
return 0;
|
||||
|
||||
/* Add the individual strings */
|
||||
for (v = strv; *v; ++v) {
|
||||
if (!egg_buffer_add_string (buffer, *v))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
egg_buffer_get_stringv (EggBuffer *buffer, size_t offset, size_t *next_offset,
|
||||
char ***strv_ret, EggBufferAllocator allocator)
|
||||
{
|
||||
uint32_t n, i, j;
|
||||
size_t len;
|
||||
|
||||
if (!allocator)
|
||||
allocator = buffer->allocator;
|
||||
if (!allocator)
|
||||
allocator = DEFAULT_ALLOCATOR;
|
||||
|
||||
/* First the number of environment variable lines */
|
||||
if (!egg_buffer_get_uint32 (buffer, offset, &offset, &n))
|
||||
return 0;
|
||||
|
||||
/* Then that number of strings */
|
||||
len = (n + 1) * sizeof (char*);
|
||||
*strv_ret = (char**)(allocator) (NULL, len);
|
||||
if (!*strv_ret)
|
||||
return 0;
|
||||
|
||||
/* All null strings */
|
||||
memset (*strv_ret, 0, len);
|
||||
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (!egg_buffer_get_string (buffer, offset, &offset,
|
||||
&((*strv_ret)[i]), allocator)) {
|
||||
|
||||
/* Free all the strings on failure */
|
||||
for (j = 0; j < i; ++j) {
|
||||
if ((*strv_ret)[j])
|
||||
(allocator) ((*strv_ret)[j], 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (next_offset != NULL)
|
||||
*next_offset = offset;
|
||||
|
||||
return 1;
|
||||
}
|
196
egg/egg-buffer.h
Normal file
196
egg/egg-buffer.h
Normal file
@ -0,0 +1,196 @@
|
||||
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
|
||||
/* egg-buffer.h - Generic data buffer, used by openssh, gnome-keyring
|
||||
|
||||
Copyright (C) 2007, Stefan Walter
|
||||
|
||||
The Gnome Keyring Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The Gnome Keyring Library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the Gnome Library; see the file COPYING.LIB. If not,
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
Author: Stef Walter <stef@memberwebs.com>
|
||||
*/
|
||||
|
||||
#ifndef EGG_BUFFER_H
|
||||
#define EGG_BUFFER_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* -------------------------------------------------------------------
|
||||
* EggBuffer
|
||||
*
|
||||
* IMPORTANT: This is pure vanila standard C, no glib. We need this
|
||||
* because certain consumers of this protocol need to be built
|
||||
* without linking in any special libraries. ie: the PKCS#11 module.
|
||||
*
|
||||
* Memory Allocation
|
||||
*
|
||||
* Callers can set their own allocator. If NULL is used then standard
|
||||
* C library heap memory is used and failures will not be fatal. Memory
|
||||
* failures will instead result in a zero return value or
|
||||
* egg_buffer_has_error() returning one.
|
||||
*
|
||||
* If you use something like g_realloc as the allocator, then memory
|
||||
* failures become fatal just like in a standard GTK program.
|
||||
*
|
||||
* Don't change the allocator manually in the EggBuffer structure. The
|
||||
* egg_buffer_set_allocator() func will reallocate and handle things
|
||||
* properly.
|
||||
*
|
||||
* Pointers into the Buffer
|
||||
*
|
||||
* Any write operation has the posibility of reallocating memory
|
||||
* and invalidating any direct pointers into the buffer.
|
||||
*/
|
||||
|
||||
/* The allocator for the EggBuffer. This follows the realloc() syntax and logic */
|
||||
typedef void* (*EggBufferAllocator) (void* p, size_t len);
|
||||
|
||||
typedef struct _EggBuffer {
|
||||
unsigned char *buf;
|
||||
size_t len;
|
||||
size_t allocated_len;
|
||||
int failures;
|
||||
EggBufferAllocator allocator;
|
||||
} EggBuffer;
|
||||
|
||||
#define EGG_BUFFER_EMPTY { NULL, 0, 0, 0, NULL }
|
||||
|
||||
int egg_buffer_init (EggBuffer *buffer, size_t reserve);
|
||||
|
||||
int egg_buffer_init_full (EggBuffer *buffer,
|
||||
size_t reserve,
|
||||
EggBufferAllocator allocator);
|
||||
|
||||
void egg_buffer_init_static (EggBuffer *buffer,
|
||||
const unsigned char *buf,
|
||||
size_t len);
|
||||
|
||||
void egg_buffer_init_allocated (EggBuffer *buffer,
|
||||
unsigned char *buf,
|
||||
size_t len,
|
||||
EggBufferAllocator allocator);
|
||||
|
||||
void egg_buffer_uninit (EggBuffer *buffer);
|
||||
|
||||
unsigned char* egg_buffer_uninit_steal (EggBuffer *buffer,
|
||||
size_t *n_result);
|
||||
|
||||
int egg_buffer_set_allocator (EggBuffer *buffer,
|
||||
EggBufferAllocator allocator);
|
||||
|
||||
void egg_buffer_reset (EggBuffer *buffer);
|
||||
|
||||
int egg_buffer_equal (EggBuffer *b1,
|
||||
EggBuffer *b2);
|
||||
|
||||
int egg_buffer_reserve (EggBuffer *buffer,
|
||||
size_t len);
|
||||
|
||||
int egg_buffer_resize (EggBuffer *buffer,
|
||||
size_t len);
|
||||
|
||||
int egg_buffer_append (EggBuffer *buffer,
|
||||
const unsigned char *val,
|
||||
size_t len);
|
||||
|
||||
unsigned char* egg_buffer_add_empty (EggBuffer *buffer,
|
||||
size_t len);
|
||||
|
||||
int egg_buffer_add_byte (EggBuffer *buffer,
|
||||
unsigned char val);
|
||||
|
||||
int egg_buffer_get_byte (EggBuffer *buffer,
|
||||
size_t offset,
|
||||
size_t *next_offset,
|
||||
unsigned char *val);
|
||||
|
||||
void egg_buffer_encode_uint32 (unsigned char* buf,
|
||||
uint32_t val);
|
||||
|
||||
uint32_t egg_buffer_decode_uint32 (unsigned char* buf);
|
||||
|
||||
int egg_buffer_add_uint32 (EggBuffer *buffer,
|
||||
uint32_t val);
|
||||
|
||||
int egg_buffer_set_uint32 (EggBuffer *buffer,
|
||||
size_t offset,
|
||||
uint32_t val);
|
||||
|
||||
int egg_buffer_get_uint32 (EggBuffer *buffer,
|
||||
size_t offset,
|
||||
size_t *next_offset,
|
||||
uint32_t *val);
|
||||
|
||||
void egg_buffer_encode_uint16 (unsigned char* buf,
|
||||
uint16_t val);
|
||||
|
||||
uint16_t egg_buffer_decode_uint16 (unsigned char* buf);
|
||||
|
||||
int egg_buffer_add_uint16 (EggBuffer *buffer,
|
||||
uint16_t val);
|
||||
|
||||
int egg_buffer_set_uint16 (EggBuffer *buffer,
|
||||
size_t offset,
|
||||
uint16_t val);
|
||||
|
||||
int egg_buffer_get_uint16 (EggBuffer *buffer,
|
||||
size_t offset,
|
||||
size_t *next_offset,
|
||||
uint16_t *val);
|
||||
|
||||
int egg_buffer_add_byte_array (EggBuffer *buffer,
|
||||
const unsigned char *val,
|
||||
size_t len);
|
||||
|
||||
int egg_buffer_get_byte_array (EggBuffer *buffer,
|
||||
size_t offset,
|
||||
size_t *next_offset,
|
||||
const unsigned char **val,
|
||||
size_t *vlen);
|
||||
|
||||
unsigned char* egg_buffer_add_byte_array_empty (EggBuffer *buffer,
|
||||
size_t vlen);
|
||||
|
||||
int egg_buffer_add_string (EggBuffer *buffer,
|
||||
const char *str);
|
||||
|
||||
int egg_buffer_get_string (EggBuffer *buffer,
|
||||
size_t offset,
|
||||
size_t *next_offset,
|
||||
char **str_ret,
|
||||
EggBufferAllocator allocator);
|
||||
|
||||
int egg_buffer_add_stringv (EggBuffer *buffer,
|
||||
const char** strv);
|
||||
|
||||
int egg_buffer_get_stringv (EggBuffer *buffer,
|
||||
size_t offset,
|
||||
size_t *next_offset,
|
||||
char ***strv_ret,
|
||||
EggBufferAllocator allocator);
|
||||
|
||||
int egg_buffer_add_uint64 (EggBuffer *buffer,
|
||||
uint64_t val);
|
||||
|
||||
int egg_buffer_get_uint64 (EggBuffer *buffer,
|
||||
size_t offset,
|
||||
size_t *next_offset,
|
||||
uint64_t *val);
|
||||
|
||||
#define egg_buffer_length(b) ((b)->len)
|
||||
|
||||
#define egg_buffer_has_error(b) ((b)->failures > 0)
|
||||
|
||||
#endif /* EGG_BUFFER_H */
|
||||
|
265
egg/egg-unix-credentials.c
Normal file
265
egg/egg-unix-credentials.c
Normal file
@ -0,0 +1,265 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Stefan Walter
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the
|
||||
* above copyright notice, this list of conditions and
|
||||
* the following disclaimer in the documentation and/or
|
||||
* other materials provided with the distribution.
|
||||
* * The names of contributors to this software may not be
|
||||
* used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* Author: Stef Walter <stefw@thewalter.net>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "egg-unix-credentials.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/un.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#if defined(HAVE_GETPEERUCRED)
|
||||
#include <ucred.h>
|
||||
#endif
|
||||
|
||||
int
|
||||
egg_unix_credentials_read (int sock, pid_t *pid, uid_t *uid)
|
||||
{
|
||||
struct msghdr msg;
|
||||
struct iovec iov;
|
||||
char buf;
|
||||
int ret;
|
||||
|
||||
#if defined(HAVE_CMSGCRED) || defined(LOCAL_CREDS)
|
||||
/* Prefer CMSGCRED over LOCAL_CREDS because the former provides the
|
||||
* remote PID. */
|
||||
#if defined(HAVE_CMSGCRED)
|
||||
struct cmsgcred *cred;
|
||||
#else /* defined(LOCAL_CREDS) */
|
||||
struct sockcred *cred;
|
||||
#endif
|
||||
union {
|
||||
struct cmsghdr hdr;
|
||||
char cred[CMSG_SPACE (sizeof *cred)];
|
||||
} cmsg;
|
||||
#endif
|
||||
|
||||
*pid = 0;
|
||||
*uid = 0;
|
||||
|
||||
/* If LOCAL_CREDS are used in this platform, they have already been
|
||||
* initialized by init_connection prior to sending of the credentials
|
||||
* byte we receive below. */
|
||||
|
||||
iov.iov_base = &buf;
|
||||
iov.iov_len = 1;
|
||||
|
||||
memset (&msg, 0, sizeof (msg));
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
#if defined(HAVE_CMSGCRED) || defined(LOCAL_CREDS)
|
||||
memset (&cmsg, 0, sizeof (cmsg));
|
||||
msg.msg_control = (caddr_t) &cmsg;
|
||||
msg.msg_controllen = CMSG_SPACE(sizeof *cred);
|
||||
#endif
|
||||
|
||||
again:
|
||||
ret = recvmsg (sock, &msg, 0);
|
||||
|
||||
if (ret < 0) {
|
||||
if (errno == EINTR)
|
||||
goto again;
|
||||
return -1;
|
||||
|
||||
} else if (ret == 0) {
|
||||
/* Disconnected */
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (buf != '\0') {
|
||||
fprintf (stderr, "credentials byte was not nul\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if defined(HAVE_CMSGCRED) || defined(LOCAL_CREDS)
|
||||
if (cmsg.hdr.cmsg_len < CMSG_LEN (sizeof *cred) ||
|
||||
cmsg.hdr.cmsg_type != SCM_CREDS) {
|
||||
fprintf (stderr, "message from recvmsg() was not SCM_CREDS\n");
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
#ifdef SO_PEERCRED
|
||||
#ifndef __OpenBSD__
|
||||
struct ucred cr;
|
||||
#else
|
||||
struct sockpeercred cr;
|
||||
#endif
|
||||
socklen_t cr_len = sizeof (cr);
|
||||
|
||||
if (getsockopt (sock, SOL_SOCKET, SO_PEERCRED, &cr, &cr_len) == 0 &&
|
||||
cr_len == sizeof (cr)) {
|
||||
*pid = cr.pid;
|
||||
*uid = cr.uid;
|
||||
} else {
|
||||
fprintf (stderr, "failed to getsockopt() credentials, returned len %d/%d\n",
|
||||
cr_len, (int) sizeof (cr));
|
||||
return -1;
|
||||
}
|
||||
#elif defined(HAVE_CMSGCRED)
|
||||
cred = (struct cmsgcred *) CMSG_DATA (&cmsg.hdr);
|
||||
*pid = cred->cmcred_pid;
|
||||
*uid = cred->cmcred_euid;
|
||||
#elif defined(LOCAL_CREDS)
|
||||
cred = (struct sockcred *) CMSG_DATA (&cmsg.hdr);
|
||||
*pid = 0;
|
||||
*uid = cred->sc_euid;
|
||||
set_local_creds(sock, 0);
|
||||
#elif defined(HAVE_GETPEEREID) /* OpenBSD */
|
||||
uid_t euid;
|
||||
gid_t egid;
|
||||
*pid = 0;
|
||||
|
||||
if (getpeereid (sock, &euid, &egid) == 0) {
|
||||
*uid = euid;
|
||||
} else {
|
||||
fprintf (stderr, "getpeereid() failed: %s\n", strerror (errno));
|
||||
return -1;
|
||||
}
|
||||
#elif defined(HAVE_GETPEERUCRED)
|
||||
ucred_t *uc = NULL;
|
||||
|
||||
if (getpeerucred (sock, &uc) == 0) {
|
||||
*pid = ucred_getpid (uc);
|
||||
*uid = ucred_geteuid (uc);
|
||||
ucred_free (uc);
|
||||
} else {
|
||||
fprintf (stderr, "getpeerucred() failed: %s\n", strerror (errno));
|
||||
return -1;
|
||||
}
|
||||
#else /* !SO_PEERCRED && !HAVE_CMSGCRED */
|
||||
fprintf (stderr, "socket credentials not supported on this OS\n");
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
egg_unix_credentials_write (int socket)
|
||||
{
|
||||
char buf;
|
||||
int bytes_written;
|
||||
#if defined(HAVE_CMSGCRED) && (!defined(LOCAL_CREDS) || defined(__FreeBSD__))
|
||||
union {
|
||||
struct cmsghdr hdr;
|
||||
char cred[CMSG_SPACE (sizeof (struct cmsgcred))];
|
||||
} cmsg;
|
||||
struct iovec iov;
|
||||
struct msghdr msg;
|
||||
#endif
|
||||
|
||||
buf = 0;
|
||||
|
||||
#if defined(HAVE_CMSGCRED) && (!defined(LOCAL_CREDS) || defined(__FreeBSD__))
|
||||
iov.iov_base = &buf;
|
||||
iov.iov_len = 1;
|
||||
|
||||
memset (&msg, 0, sizeof (msg));
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
msg.msg_control = (caddr_t) &cmsg;
|
||||
msg.msg_controllen = CMSG_SPACE (sizeof (struct cmsgcred));
|
||||
memset (&cmsg, 0, sizeof (cmsg));
|
||||
cmsg.hdr.cmsg_len = CMSG_LEN (sizeof (struct cmsgcred));
|
||||
cmsg.hdr.cmsg_level = SOL_SOCKET;
|
||||
cmsg.hdr.cmsg_type = SCM_CREDS;
|
||||
#endif
|
||||
|
||||
again:
|
||||
|
||||
#if defined(HAVE_CMSGCRED) && (!defined(LOCAL_CREDS) || defined(__FreeBSD__))
|
||||
bytes_written = sendmsg (socket, &msg, 0);
|
||||
#else
|
||||
bytes_written = write (socket, &buf, 1);
|
||||
#endif
|
||||
|
||||
if (bytes_written < 0 && errno == EINTR)
|
||||
goto again;
|
||||
|
||||
if (bytes_written <= 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
egg_unix_credentials_setup (int sock)
|
||||
{
|
||||
int retval = 0;
|
||||
#if defined(LOCAL_CREDS) && !defined(HAVE_CMSGCRED)
|
||||
int val = 1;
|
||||
if (setsockopt (sock, 0, LOCAL_CREDS, &val, sizeof (val)) < 0) {
|
||||
fprintf (stderr, "unable to set LOCAL_CREDS socket option on fd %d\n", fd);
|
||||
retval = -1;
|
||||
}
|
||||
#endif
|
||||
return retval;
|
||||
}
|
||||
|
||||
char*
|
||||
egg_unix_credentials_executable (pid_t pid)
|
||||
{
|
||||
char *result = NULL;
|
||||
|
||||
/* Try and figure out the path from the pid */
|
||||
#if defined(__linux__) || defined(__FreeBSD__)
|
||||
char path[1024];
|
||||
char buffer[64];
|
||||
int count;
|
||||
|
||||
#if defined(__linux__)
|
||||
snprintf (buffer, sizeof (buffer), "/proc/%d/exe", (int)pid);
|
||||
#elif defined(__FreeBSD__)
|
||||
snprintf (buffer, sizeof (buffer), "/proc/%d/file", (int)pid);
|
||||
#endif
|
||||
|
||||
count = readlink (buffer, path, sizeof (path));
|
||||
if (count < 0)
|
||||
fprintf (stderr, "readlink failed for file: %s", buffer);
|
||||
else
|
||||
result = strndup (path, count);
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
50
egg/egg-unix-credentials.h
Normal file
50
egg/egg-unix-credentials.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Stefan Walter
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above
|
||||
* copyright notice, this list of conditions and the
|
||||
* following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the
|
||||
* above copyright notice, this list of conditions and
|
||||
* the following disclaimer in the documentation and/or
|
||||
* other materials provided with the distribution.
|
||||
* * The names of contributors to this software may not be
|
||||
* used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* Author: Stef Walter <stefw@thewalter.net>
|
||||
*/
|
||||
|
||||
#ifndef EGGUNIXCREDENTIALS_H_
|
||||
#define EGGUNIXCREDENTIALS_H_
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
int egg_unix_credentials_read (int sock,
|
||||
pid_t *pid,
|
||||
uid_t *uid);
|
||||
|
||||
int egg_unix_credentials_write (int sock);
|
||||
|
||||
int egg_unix_credentials_setup (int sock);
|
||||
|
||||
char* egg_unix_credentials_executable (pid_t pid);
|
||||
|
||||
#endif /*EGGUNIXCREDENTIALS_H_*/
|
@ -1,6 +1,8 @@
|
||||
libegg_sources = [
|
||||
'egg-hex.c',
|
||||
'egg-secure-memory.c',
|
||||
'egg-unix-credentials.c',
|
||||
'egg-buffer.c',
|
||||
'egg-testing.c',
|
||||
]
|
||||
|
||||
@ -42,6 +44,9 @@ endif
|
||||
libegg = static_library('egg',
|
||||
libegg_sources,
|
||||
dependencies: libegg_deps,
|
||||
c_args: [
|
||||
'-D_GNU_SOURCE',
|
||||
],
|
||||
include_directories: [config_h_dir, build_dir],
|
||||
)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user