gc_malloc (size_t size, bool clear, struct gc_arena *a) #endif { void *ret; if (a) { struct gc_entry *e; #ifdef DMALLOC e = (struct gc_entry *) openvpn_dmalloc (file, line, size + sizeof (struct gc_entry)); #else e = (struct gc_entry *) malloc (size + sizeof (struct gc_entry)); #endif check_malloc_return (e); ret = (char *) e + sizeof (struct gc_entry); e->next = a->list; a->list = e; } else { #ifdef DMALLOC ret = openvpn_dmalloc (file, line, size); #else ret = malloc (size); #endif check_malloc_return (ret); } #ifndef ZERO_BUFFER_ON_ALLOC if (clear) #endif memset (ret, 0, size); return ret; }
static char * env_block (const struct env_set *es) { if (es) { struct env_item *e; char *ret; char *p; size_t nchars = 1; for (e = es->list; e != NULL; e = e->next) nchars += strlen (e->string) + 1; ret = (char *) malloc (nchars); check_malloc_return (ret); p = ret; for (e = es->list; e != NULL; e = e->next) { if (env_allowed (e->string)) { strcpy (p, e->string); p += strlen (e->string) + 1; } } *p = '\0'; return ret; } else return NULL; }
static char * env_block(const struct env_set *es) { char force_path[256]; char *sysroot = get_win_sys_path(); if (!openvpn_snprintf(force_path, sizeof(force_path), "PATH=%s\\System32;%s;%s\\System32\\Wbem", sysroot, sysroot, sysroot)) { msg(M_WARN, "env_block: default path truncated to %s", force_path); } if (es) { struct env_item *e; char *ret; char *p; size_t nchars = 1; bool path_seen = false; for (e = es->list; e != NULL; e = e->next) { nchars += strlen(e->string) + 1; } nchars += strlen(force_path)+1; ret = (char *) malloc(nchars); check_malloc_return(ret); p = ret; for (e = es->list; e != NULL; e = e->next) { if (env_allowed(e->string)) { strcpy(p, e->string); p += strlen(e->string) + 1; } if (strncmp(e->string, "PATH=", 5 ) == 0) { path_seen = true; } } /* make sure PATH is set */ if (!path_seen) { msg( M_INFO, "env_block: add %s", force_path ); strcpy( p, force_path ); p += strlen(force_path) + 1; } *p = '\0'; return ret; } else { return NULL; } }
static void argv_system_str_append (struct argv *a, const char *str, const bool enquote) { if (str) { char *newstr; /* compute length of new system_str */ size_t l = strlen (str) + 1; /* space for new string plus trailing '\0' */ if (a->system_str) l += strlen (a->system_str) + 1; /* space for existing string + space (" ") separator */ if (enquote) l += 2; /* space for two quotes */ /* build new system_str */ newstr = (char *) malloc (l); newstr[0] = '\0'; check_malloc_return (newstr); if (a->system_str) { strcpy (newstr, a->system_str); strcat (newstr, " "); } if (enquote) strcat (newstr, "\""); strcat (newstr, str); if (enquote) strcat (newstr, "\""); free (a->system_str); a->system_str = newstr; } }
HMAC_CTX * hmac_ctx_new(void) { HMAC_CTX *ctx = HMAC_CTX_new(); check_malloc_return(ctx); return ctx; }
cipher_ctx_t * cipher_ctx_new(void) { EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); check_malloc_return(ctx); return ctx; }
static bool pkcs11_get_x509_cert(pkcs11h_certificate_t pkcs11_cert, mbedtls_x509_crt *cert) { unsigned char *cert_blob = NULL; size_t cert_blob_size = 0; bool ret = false; if (pkcs11h_certificate_getCertificateBlob(pkcs11_cert, NULL, &cert_blob_size) != CKR_OK) { msg(M_WARN, "PKCS#11: Cannot retrieve certificate object size"); goto cleanup; } check_malloc_return((cert_blob = calloc(1, cert_blob_size))); if (pkcs11h_certificate_getCertificateBlob(pkcs11_cert, cert_blob, &cert_blob_size) != CKR_OK) { msg(M_WARN, "PKCS#11: Cannot retrieve certificate object"); goto cleanup; } if (!mbed_ok(mbedtls_x509_crt_parse(cert, cert_blob, cert_blob_size))) { msg(M_WARN, "PKCS#11: Could not parse certificate"); goto cleanup; } ret = true; cleanup: free(cert_blob); return ret; }
string_alloc (const char *str, struct gc_arena *gc) #endif { if (str) { const int n = strlen (str) + 1; char *ret; if (gc) { #ifdef DMALLOC ret = (char *) gc_malloc_debug (n, false, gc, file, line); #else ret = (char *) gc_malloc (n, false, gc); #endif } else { /* If there are no garbage collector available, it's expected * that the caller cleans up afterwards. This is coherent with the * earlier behaviour when gc_malloc() would be called with gc == NULL */ #ifdef DMALLOC ret = openvpn_dmalloc (file, line, n); memset(ret, 0, n); #else ret = calloc(1, n); #endif check_malloc_return(ret); } memcpy (ret, str, n); return ret; } else return NULL; }
EVP_MD_CTX * md_ctx_new(void) { EVP_MD_CTX *ctx = EVP_MD_CTX_new(); check_malloc_return(ctx); return ctx; }
static WCHAR * wide_cmd_line(const struct argv *a, struct gc_arena *gc) { size_t nchars = 1; size_t maxlen = 0; size_t i; struct buffer buf; char *work = NULL; if (!a) { return NULL; } for (i = 0; i < a->argc; ++i) { const char *arg = a->argv[i]; const size_t len = strlen(arg); nchars += len + 3; if (len > maxlen) { maxlen = len; } } work = gc_malloc(maxlen + 1, false, gc); check_malloc_return(work); buf = alloc_buf_gc(nchars, gc); for (i = 0; i < a->argc; ++i) { const char *arg = a->argv[i]; strcpy(work, arg); string_mod(work, CC_PRINT, CC_DOUBLE_QUOTE|CC_CRLF, '_'); if (i) { buf_printf(&buf, " "); } if (string_class(work, CC_ANY, CC_SPACE)) { buf_printf(&buf, "%s", work); } else { buf_printf(&buf, "\"%s\"", work); } } return wide_string(BSTR(&buf), gc); }
static void lzo_compress_init(struct compress_context *compctx) { msg(D_INIT_MEDIUM, "LZO compression initializing"); ASSERT(!(compctx->flags & COMP_F_SWAP)); compctx->wu.lzo.wmem_size = LZO_WORKSPACE; int lzo_status = lzo_init(); if (lzo_status != LZO_E_OK) { msg(M_FATAL, "Cannot initialize LZO compression library (lzo_init() returns %d)", lzo_status); } compctx->wu.lzo.wmem = (lzo_voidp) lzo_malloc(compctx->wu.lzo.wmem_size); check_malloc_return(compctx->wu.lzo.wmem); }
/* worker method for setenv_x509_track */ static void do_setenv_x509 (struct env_set *es, const char *name, char *value, int depth) { char *name_expand; size_t name_expand_size; string_mod (value, CC_ANY, CC_CRLF, '?'); msg (D_X509_ATTR, "X509 ATTRIBUTE name='%s' value='%s' depth=%d", name, value, depth); name_expand_size = 64 + strlen (name); name_expand = (char *) malloc (name_expand_size); check_malloc_return (name_expand); openvpn_snprintf (name_expand, name_expand_size, "X509_%d_%s", depth, name); setenv_str (es, name_expand, value); free (name_expand); }
clone_buf (const struct buffer* buf) #endif { struct buffer ret; ret.capacity = buf->capacity; ret.offset = buf->offset; ret.len = buf->len; #ifdef DMALLOC ret.data = (uint8_t *) openvpn_dmalloc (file, line, buf->capacity); #else ret.data = (uint8_t *) malloc (buf->capacity); #endif check_malloc_return (ret.data); memcpy (BPTR (&ret), BPTR (buf), BLEN (buf)); return ret; }
void gc_addspecial (void *addr, void (free_function)(void*), struct gc_arena *a) { ASSERT(a); struct gc_entry_special *e; #ifdef DMALLOC e = (struct gc_entry_special *) openvpn_dmalloc (file, line, sizeof (struct gc_entry_special)); #else e = (struct gc_entry_special *) malloc (sizeof (struct gc_entry_special)); #endif check_malloc_return (e); e->free_fnc = free_function; e->addr = addr; e->next = a->list_special; a->list_special = e; }
static char * env_block (const struct env_set *es) { char * force_path = "PATH=C:\\Windows\\System32;C:\\WINDOWS;C:\\WINDOWS\\System32\\Wbem"; if (es) { struct env_item *e; char *ret; char *p; size_t nchars = 1; bool path_seen = false; for (e = es->list; e != NULL; e = e->next) nchars += strlen (e->string) + 1; nchars += strlen(force_path)+1; ret = (char *) malloc (nchars); check_malloc_return (ret); p = ret; for (e = es->list; e != NULL; e = e->next) { if (env_allowed (e->string)) { strcpy (p, e->string); p += strlen (e->string) + 1; } if ( strncmp(e->string, "PATH=", 5 ) == 0 ) path_seen = true; } /* make sure PATH is set */ if ( !path_seen ) { msg( M_INFO, "env_block: add %s", force_path ); strcpy( p, force_path ); p += strlen(force_path) + 1; } *p = '\0'; return ret; } else return NULL; }
/* * Save X509 fields to environment, using the naming convention: * * X509_{cert_depth}_{name}={value} */ void x509_setenv (struct env_set *es, int cert_depth, openvpn_x509_cert_t *peer_cert) { int i, n; int fn_nid; ASN1_OBJECT *fn; ASN1_STRING *val; X509_NAME_ENTRY *ent; const char *objbuf; unsigned char *buf; char *name_expand; size_t name_expand_size; X509_NAME *x509 = X509_get_subject_name (peer_cert); n = X509_NAME_entry_count (x509); for (i = 0; i < n; ++i) { ent = X509_NAME_get_entry (x509, i); if (!ent) continue; fn = X509_NAME_ENTRY_get_object (ent); if (!fn) continue; val = X509_NAME_ENTRY_get_data (ent); if (!val) continue; fn_nid = OBJ_obj2nid (fn); if (fn_nid == NID_undef) continue; objbuf = OBJ_nid2sn (fn_nid); if (!objbuf) continue; buf = (unsigned char *)1; /* bug in OpenSSL 0.9.6b ASN1_STRING_to_UTF8 requires this workaround */ if (ASN1_STRING_to_UTF8 (&buf, val) <= 0) continue; name_expand_size = 64 + strlen (objbuf); name_expand = (char *) malloc (name_expand_size); check_malloc_return (name_expand); openvpn_snprintf (name_expand, name_expand_size, "X509_%d_%s", cert_depth, objbuf); string_mod (name_expand, CC_PRINT, CC_CRLF, '_'); string_mod ((char*)buf, CC_PRINT, CC_CRLF, '_'); setenv_str (es, name_expand, (char*)buf); free (name_expand); OPENSSL_free (buf); } }
char * argv_term (const char **f) { const char *p = *f; const char *term = NULL; size_t termlen = 0; if (*p == '\0') return NULL; while (true) { const int c = *p; if (c == '\0') break; if (term) { if (!isspace (c)) ++termlen; else break; } else { if (!isspace (c)) { term = p; termlen = 1; } } ++p; } *f = p; if (term) { char *ret; ASSERT (termlen > 0); ret = malloc (termlen + 1); check_malloc_return (ret); memcpy (ret, term, termlen); ret[termlen] = '\0'; return ret; } else return NULL; }
/* * This is exactly like clone_buf, but uses malloc to allocate the memory so that it can be cached * properly */ struct buffer* full_clone_buf(const struct buffer* buf) { struct buffer* ret = (struct buffer*) malloc(sizeof(struct buffer)); ret->capacity = buf->capacity; ret->offset = buf->offset; ret->len = buf->len; #ifdef DMALLOC ret->data = (uint8_t *) openvpn_dmalloc (file, line, buf->capacity); #else ret->data = (uint8_t *) malloc (buf->capacity); #endif check_malloc_return (ret->data); memcpy (BPTR (ret), BPTR (buf), BLEN (buf)); return ret; }
void prng_init (const char *md_name, const int nonce_secret_len_parm) { prng_uninit (); nonce_md = md_name ? md_kt_get (md_name) : NULL; if (nonce_md) { ASSERT (nonce_secret_len_parm >= NONCE_SECRET_LEN_MIN && nonce_secret_len_parm <= NONCE_SECRET_LEN_MAX); nonce_secret_len = nonce_secret_len_parm; { const int size = md_kt_size(nonce_md) + nonce_secret_len; dmsg (D_CRYPTO_DEBUG, "PRNG init md=%s size=%d", md_kt_name(nonce_md), size); nonce_data = (uint8_t*) malloc (size); check_malloc_return (nonce_data); prng_reset_nonce(); } } }
alloc_buf (size_t size) #endif { struct buffer buf; if (!buf_size_valid (size)) buf_size_error (size); buf.capacity = (int)size; buf.offset = 0; buf.len = 0; #ifdef DMALLOC buf.data = openvpn_dmalloc (file, line, size); #else buf.data = calloc (1, size); #endif check_malloc_return(buf.data); return buf; }
void buffer_list_aggregate_separator (struct buffer_list *bl, const size_t max, const char *sep) { int sep_len = strlen(sep); if (bl->head) { struct buffer_entry *more = bl->head; size_t size = 0; int count = 0; for (count = 0; more && size <= max; ++count) { size += BLEN(&more->buf) + sep_len; more = more->next; } if (count >= 2) { int i; struct buffer_entry *e = bl->head, *f; ALLOC_OBJ_CLEAR (f, struct buffer_entry); f->buf.data = malloc (size); check_malloc_return (f->buf.data); f->buf.capacity = size; for (i = 0; e && i < count; ++i) { struct buffer_entry *next = e->next; buf_copy (&f->buf, &e->buf); buf_write(&f->buf, sep, sep_len); free_buf (&e->buf); free (e); e = next; } bl->head = f; f->next = more; if (!more) bl->tail = f; } } }
static char * cmd_line (const struct argv *a) { size_t nchars = 1; size_t maxlen = 0; size_t i; struct buffer buf; char *work = NULL; if (!a) return NULL; for (i = 0; i < a->argc; ++i) { const char *arg = a->argv[i]; const size_t len = strlen (arg); nchars += len + 3; if (len > maxlen) maxlen = len; } work = (char *) malloc (maxlen + 1); check_malloc_return (work); buf = alloc_buf (nchars); for (i = 0; i < a->argc; ++i) { const char *arg = a->argv[i]; strcpy (work, arg); string_mod (work, CC_PRINT, CC_DOUBLE_QUOTE|CC_CRLF, '_'); if (i) buf_printf (&buf, " "); if (string_class (work, CC_ANY, CC_SPACE)) buf_printf (&buf, "%s", work); else buf_printf (&buf, "\"%s\"", work); } free (work); return BSTR(&buf); }
/* * Record IP/port of client in filesystem, so that server receiving * the proxy can determine true client origin. */ static void journal_add(const char *journal_dir, struct proxy_connection *pc, struct proxy_connection *cp) { struct gc_arena gc = gc_new(); struct openvpn_sockaddr from, to; socklen_t slen, dlen; int fnlen; char *jfn; int fd; slen = sizeof(from.addr.sa); dlen = sizeof(to.addr.sa); if (!getpeername(pc->sd, (struct sockaddr *) &from.addr.sa, &slen) && !getsockname(cp->sd, (struct sockaddr *) &to.addr.sa, &dlen)) { const char *f = print_openvpn_sockaddr(&from, &gc); const char *t = print_openvpn_sockaddr(&to, &gc); fnlen = strlen(journal_dir) + strlen(t) + 2; jfn = (char *) malloc(fnlen); check_malloc_return(jfn); openvpn_snprintf(jfn, fnlen, "%s/%s", journal_dir, t); dmsg(D_PS_PROXY_DEBUG, "PORT SHARE PROXY: client origin %s -> %s", jfn, f); fd = platform_open(jfn, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP); if (fd != -1) { if (write(fd, f, strlen(f)) != strlen(f)) { msg(M_WARN, "PORT SHARE: writing to journal file (%s) failed", jfn); } close(fd); cp->jfn = jfn; } else { msg(M_WARN|M_ERRNO, "PORT SHARE: unable to write journal file in %s", jfn); free(jfn); } } gc_free(&gc); }
static void err_put_ms_error(DWORD ms_err, int func, const char *file, int line) { static int init = 0; # define ERR_MAP_SZ 16 static struct { int err; DWORD ms_err; /* I don't think we get more than 16 *different* errors */ } err_map[ERR_MAP_SZ]; /* in here, before we give up the whole thing... */ int i; if (ms_err == 0) /* 0 is not an error */ return; if (!init) { ERR_load_strings(ERR_LIB_CRYPTOAPI, CRYPTOAPI_str_functs); memset(&err_map, 0, sizeof(err_map)); init++; } /* since MS error codes are 32 bit, and the ones in the ERR_... system is * only 12, we must have a mapping table between them. */ for (i = 0; i < ERR_MAP_SZ; i++) { if (err_map[i].ms_err == ms_err) { ERR_PUT_error(ERR_LIB_CRYPTOAPI, func, err_map[i].err, file, line); break; } else if (err_map[i].ms_err == 0 ) { /* end of table, add new entry */ ERR_STRING_DATA *esd = calloc(2, sizeof(*esd)); if (esd == NULL) break; err_map[i].ms_err = ms_err; err_map[i].err = esd->error = i + 100; esd->string = ms_error_text(ms_err); check_malloc_return(esd->string); ERR_load_strings(ERR_LIB_CRYPTOAPI, esd); ERR_PUT_error(ERR_LIB_CRYPTOAPI, func, err_map[i].err, file, line); break; } } }
char * _openssl_get_subject (X509 *cert, char *buf, int size) { BIO *subject_bio = NULL; BUF_MEM *subject_mem; char *subject = buf; int maxlen = size; subject_bio = BIO_new (BIO_s_mem ()); if (subject_bio == NULL) goto err; X509_NAME_print_ex (subject_bio, X509_get_subject_name (cert), 0, XN_FLAG_SEP_CPLUS_SPC | XN_FLAG_FN_SN | ASN1_STRFLGS_UTF8_CONVERT | ASN1_STRFLGS_ESC_CTRL); if (BIO_eof (subject_bio)) goto err; BIO_get_mem_ptr (subject_bio, &subject_mem); if (subject == NULL) { maxlen = subject_mem->length + 1; subject = malloc (maxlen); check_malloc_return (subject); } memcpy (subject, subject_mem->data, maxlen); subject[maxlen - 1] = '\0'; err: if (subject_bio) BIO_free (subject_bio); return subject; }
/* * This function runs in the context of the background proxy process. * Receive a control message from the parent (sent by the port_share_sendmsg * function above) and act on it. Return false if the proxy process should * exit, true otherwise. */ static bool control_message_from_parent (const socket_descriptor_t sd_control, struct proxy_connection **list, struct event_set *es, const in_addr_t server_addr, const int server_port, const int max_initial_buf, const char *journal_dir) { /* this buffer needs to be large enough to handle the largest buffer that might be returned by the link_socket_read call in read_incoming_link. */ struct buffer buf = alloc_buf (max_initial_buf); struct msghdr mesg; struct cmsghdr* h; struct iovec iov[2]; char command = 0; ssize_t status; int ret = true; CLEAR (mesg); iov[0].iov_base = &command; iov[0].iov_len = sizeof (command); iov[1].iov_base = BPTR (&buf); iov[1].iov_len = BCAP (&buf); mesg.msg_iov = iov; mesg.msg_iovlen = 2; mesg.msg_controllen = cmsg_size (); mesg.msg_control = (char *) malloc (mesg.msg_controllen); check_malloc_return (mesg.msg_control); mesg.msg_flags = 0; h = CMSG_FIRSTHDR(&mesg); h->cmsg_len = CMSG_LEN(sizeof(socket_descriptor_t)); h->cmsg_level = SOL_SOCKET; h->cmsg_type = SCM_RIGHTS; *((socket_descriptor_t*)CMSG_DATA(h)) = SOCKET_UNDEFINED; status = recvmsg (sd_control, &mesg, MSG_NOSIGNAL); if (status != -1) { if ( h == NULL || h->cmsg_len != CMSG_LEN(sizeof(socket_descriptor_t)) || h->cmsg_level != SOL_SOCKET || h->cmsg_type != SCM_RIGHTS ) { msg (M_WARN, "PORT SHARE PROXY: received unknown message"); } else { const socket_descriptor_t received_fd = *((socket_descriptor_t*)CMSG_DATA(h)); dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: RECEIVED sd=%d", (int)received_fd); if (status >= 2 && command == COMMAND_REDIRECT) { buf.len = status - 1; if (proxy_entry_new (list, es, server_addr, server_port, received_fd, &buf, journal_dir)) { CLEAR (buf); /* we gave the buffer to proxy_entry_new */ } else { openvpn_close_socket (received_fd); } } else if (status >= 1 && command == COMMAND_EXIT) { dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: RECEIVED COMMAND_EXIT"); openvpn_close_socket (received_fd); /* null socket */ ret = false; } } } free (mesg.msg_control); free_buf (&buf); return ret; }
/* * Send a command (char), data (head), and a file descriptor (sd_send) to a local process * over unix socket sd. Unfortunately, there's no portable way to send file descriptors * to other processes, so this code, as well as its analog (control_message_from_parent below), * is Linux-specific. This function runs in the context of the main process and is used to * send commands, data, and file descriptors to the background process. */ static void port_share_sendmsg (const socket_descriptor_t sd, const char command, const struct buffer *head, const socket_descriptor_t sd_send) { if (socket_defined (sd)) { struct msghdr mesg; struct cmsghdr* h; struct iovec iov[2]; socket_descriptor_t sd_null[2] = { SOCKET_UNDEFINED, SOCKET_UNDEFINED }; char cmd; ssize_t status; dmsg (D_PS_PROXY_DEBUG, "PORT SHARE: sendmsg sd=%d len=%d", (int)sd_send, head ? BLEN(head) : -1); CLEAR (mesg); cmd = command; iov[0].iov_base = &cmd; iov[0].iov_len = sizeof (cmd); mesg.msg_iovlen = 1; if (head) { iov[1].iov_base = BPTR (head); iov[1].iov_len = BLEN (head); mesg.msg_iovlen = 2; } mesg.msg_iov = iov; mesg.msg_controllen = cmsg_size (); mesg.msg_control = (char *) malloc (mesg.msg_controllen); check_malloc_return (mesg.msg_control); mesg.msg_flags = 0; h = CMSG_FIRSTHDR(&mesg); h->cmsg_level = SOL_SOCKET; h->cmsg_type = SCM_RIGHTS; h->cmsg_len = CMSG_LEN(sizeof(socket_descriptor_t)); if (socket_defined (sd_send)) { *((socket_descriptor_t*)CMSG_DATA(h)) = sd_send; } else { socketpair (PF_UNIX, SOCK_DGRAM, 0, sd_null); *((socket_descriptor_t*)CMSG_DATA(h)) = sd_null[0]; } status = sendmsg (sd, &mesg, MSG_NOSIGNAL); if (status == -1) msg (M_WARN|M_ERRNO, "PORT SHARE: sendmsg failed -- unable to communicate with background process (%d,%d,%d,%d)", sd, sd_send, sd_null[0], sd_null[1] ); close_socket_if_defined (sd_null[0]); close_socket_if_defined (sd_null[1]); free (mesg.msg_control); } }