| /* |
| * Copyright (c) 1997-8 Andrew G Morgan <morgan@kernel.org> |
| * |
| * This file deals with allocation and deallocation of internal |
| * capability sets as specified by POSIX.1e (formerlly, POSIX 6). |
| */ |
| |
| #include "libcap.h" |
| |
| /* |
| * Obtain a blank set of capabilities |
| */ |
| |
| cap_t cap_init(void) |
| { |
| __u32 *raw_data; |
| cap_t result; |
| |
| raw_data = malloc( sizeof(__u32) + sizeof(*result) ); |
| |
| if (raw_data == NULL) { |
| _cap_debug("out of memory"); |
| errno = ENOMEM; |
| return NULL; |
| } |
| |
| *raw_data = CAP_T_MAGIC; |
| result = (cap_t) (raw_data + 1); |
| memset(result, 0, sizeof(*result)); |
| |
| result->head.version = _LIBCAP_CAPABILITY_VERSION; |
| capget(&result->head, NULL); /* load the kernel-capability version */ |
| |
| switch (result->head.version) { |
| #ifdef _LINUX_CAPABILITY_VERSION_1 |
| case _LINUX_CAPABILITY_VERSION_1: |
| break; |
| #endif |
| #ifdef _LINUX_CAPABILITY_VERSION_2 |
| case _LINUX_CAPABILITY_VERSION_2: |
| break; |
| #endif |
| #ifdef _LINUX_CAPABILITY_VERSION_3 |
| case _LINUX_CAPABILITY_VERSION_3: |
| break; |
| #endif |
| default: /* No idea what to do */ |
| cap_free(result); |
| result = NULL; |
| break; |
| } |
| |
| return result; |
| } |
| |
| /* |
| * This is an internal library function to duplicate a string and |
| * tag the result as something cap_free can handle. |
| */ |
| |
| char *_libcap_strdup(const char *old) |
| { |
| __u32 *raw_data; |
| |
| if (old == NULL) { |
| errno = EINVAL; |
| return NULL; |
| } |
| |
| raw_data = malloc( sizeof(__u32) + strlen(old) + 1 ); |
| if (raw_data == NULL) { |
| errno = ENOMEM; |
| return NULL; |
| } |
| |
| *(raw_data++) = CAP_S_MAGIC; |
| strcpy((char *) raw_data, old); |
| |
| return ((char *) raw_data); |
| } |
| |
| /* |
| * This function duplicates an internal capability set with |
| * malloc()'d memory. It is the responsibility of the user to call |
| * cap_free() to liberate it. |
| */ |
| |
| cap_t cap_dup(cap_t cap_d) |
| { |
| cap_t result; |
| |
| if (!good_cap_t(cap_d)) { |
| _cap_debug("bad argument"); |
| errno = EINVAL; |
| return NULL; |
| } |
| |
| result = cap_init(); |
| if (result == NULL) { |
| _cap_debug("out of memory"); |
| return NULL; |
| } |
| |
| memcpy(result, cap_d, sizeof(*cap_d)); |
| |
| return result; |
| } |
| |
| |
| /* |
| * Scrub and then liberate an internal capability set. |
| */ |
| |
| int cap_free(void *data_p) |
| { |
| if ( !data_p ) |
| return 0; |
| |
| if ( good_cap_t(data_p) ) { |
| data_p = -1 + (__u32 *) data_p; |
| memset(data_p, 0, sizeof(__u32) + sizeof(struct _cap_struct)); |
| free(data_p); |
| data_p = NULL; |
| return 0; |
| } |
| |
| if ( good_cap_string(data_p) ) { |
| int length = strlen(data_p) + sizeof(__u32); |
| data_p = -1 + (__u32 *) data_p; |
| memset(data_p, 0, length); |
| free(data_p); |
| data_p = NULL; |
| return 0; |
| } |
| |
| _cap_debug("don't recognize what we're supposed to liberate"); |
| errno = EINVAL; |
| return -1; |
| } |