/* * Auth username/password * * Client received an authentication failed message from server. * Runs on client. */ void receive_auth_failed (struct context *c, const struct buffer *buffer) { msg (M_VERB0, "AUTH: Received control message: %s", BSTR(buffer)); c->options.no_advance=true; if (c->options.pull) { switch (auth_retry_get ()) { case AR_NONE: c->sig->signal_received = SIGTERM; /* SOFT-SIGTERM -- Auth failure error */ break; case AR_INTERACT: ssl_purge_auth (false); case AR_NOINTERACT: c->sig->signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- Auth failure error */ break; default: ASSERT (0); } c->sig->signal_text = "auth-failure"; #ifdef ENABLE_MANAGEMENT if (management) { const char *reason = NULL; struct buffer buf = *buffer; if (buf_string_compare_advance (&buf, "AUTH_FAILED,") && BLEN (&buf)) reason = BSTR (&buf); management_auth_failure (management, UP_TYPE_AUTH, reason); } else #endif { #ifdef ENABLE_CLIENT_CR struct buffer buf = *buffer; if (buf_string_match_head_str (&buf, "AUTH_FAILED,CRV1:") && BLEN (&buf)) { buf_advance (&buf, 12); /* Length of "AUTH_FAILED," substring */ ssl_put_auth_challenge (BSTR (&buf)); } #endif } } }
void process_incoming_tun (struct context *c) { struct gc_arena gc = gc_new (); perf_push (PERF_PROC_IN_TUN); if (c->c2.buf.len > 0) c->c2.tun_read_bytes += c->c2.buf.len; #ifdef LOG_RW if (c->c2.log_rw && c->c2.buf.len > 0) fprintf (stderr, "r"); #endif /* Show packet content */ dmsg (D_TUN_RW, "TUN READ [%d]", BLEN (&c->c2.buf)); if (c->c2.buf.len > 0) { /* * The --passtos and --mssfix options require * us to examine the IP header (IPv4 or IPv6). */ process_ip_header (c, PIPV4_PASSTOS|PIP_MSSFIX|PIPV4_CLIENT_NAT, &c->c2.buf); #ifdef PACKET_TRUNCATION_CHECK /* if (c->c2.buf.len > 1) --c->c2.buf.len; */ ipv4_packet_size_verify (BPTR (&c->c2.buf), BLEN (&c->c2.buf), TUNNEL_TYPE (c->c1.tuntap), "PRE_ENCRYPT", &c->c2.n_trunc_pre_encrypt); #endif encrypt_sign (c, true); } else { buf_reset (&c->c2.to_link); } perf_pop (); gc_free (&gc); }
/* * Read from an OpenSSL BIO in non-blocking mode. */ static int bio_read (BIO *bio, struct buffer *buf, int maxlen, const char *desc) { int i; int ret = 0; ASSERT (buf->len >= 0); if (buf->len) { ; } else { int len = buf_forward_capacity (buf); if (maxlen < len) len = maxlen; /* * BIO_read brackets most of the serious RSA * key negotiation number crunching. */ i = BIO_read (bio, BPTR (buf), len); VALGRIND_MAKE_READABLE ((void *) &i, sizeof (i)); #ifdef BIO_DEBUG bio_debug_data ("read", bio, BPTR (buf), i, desc); #endif if (i < 0) { if (BIO_should_retry (bio)) { ; } else { msg (D_TLS_ERRORS | M_SSL, "TLS_ERROR: BIO read %s error", desc); buf->len = 0; ret = -1; ERR_clear_error (); } } else if (!i) { buf->len = 0; } else { /* successful read */ dmsg (D_HANDSHAKE_VERBOSE, "BIO read %s %d bytes", desc, i); buf->len = i; ret = 1; VALGRIND_MAKE_READABLE ((void *) BPTR (buf), BLEN (buf)); } } return ret; }
/* Copy up to len bytes from q->bfirst to @to, leaving the block in place. May * return with less than len, but greater than 0, even if there is more * available in q. * * At any moment that we have copied anything and things are tricky, we can just * return. The trickiness comes from a bunch of variables: is the main body * empty? How do we split the ebd? If our alloc fails, then we can fall back * to @to's main body, but only if we haven't used it yet. */ static size_t copy_from_first_block(struct queue *q, struct block *to, size_t len) { struct block *from = q->bfirst; size_t copy_amt, amt; struct extra_bdata *ebd; assert(len < BLEN(from)); /* sanity */ /* Try to extract from the main body */ copy_amt = MIN(BHLEN(from), len); if (copy_amt) { copy_amt = copy_to_block_body(to, from->rp, copy_amt); from->rp += copy_amt; /* We only change dlen, (data len), not q->len, since the q still has * the same block memory allocation (no kfrees happened) */ q->dlen -= copy_amt; } /* Try to extract the remainder from the extra data */ len -= copy_amt; for (int i = 0; (i < from->nr_extra_bufs) && len; i++) { ebd = &from->extra_data[i]; if (!ebd->base || !ebd->len) continue; if (len >= ebd->len) { amt = move_ebd(ebd, to, from, q); if (!amt) { /* our internal alloc could have failed. this ebd is now the * last one we'll consider. let's handle it separately and put * it in the main body. */ if (copy_amt) return copy_amt; copy_amt = copy_to_block_body(to, (void*)ebd->base + ebd->off, ebd->len); block_and_q_lost_extra(from, q, copy_amt); break; } len -= amt; copy_amt += amt; continue; } else { /* If we're here, we reached our final ebd, which we'll need to * split to get anything from it. */ if (copy_amt) return copy_amt; copy_amt = copy_to_block_body(to, (void*)ebd->base + ebd->off, len); ebd->off += copy_amt; ebd->len -= copy_amt; block_and_q_lost_extra(from, q, copy_amt); break; } } if (len) assert(copy_amt); /* sanity */ return copy_amt; }
unsigned int mroute_extract_addr_ether(struct mroute_addr *src, struct mroute_addr *dest, struct mroute_addr *esrc, struct mroute_addr *edest, const struct buffer *buf) { unsigned int ret = 0; if (BLEN(buf) >= (int) sizeof(struct openvpn_ethhdr)) { const struct openvpn_ethhdr *eth = (const struct openvpn_ethhdr *) BPTR(buf); if (src) { src->type = MR_ADDR_ETHER; src->netbits = 0; src->len = 6; memcpy(src->eth_addr, eth->source, sizeof(dest->eth_addr)); } if (dest) { dest->type = MR_ADDR_ETHER; dest->netbits = 0; dest->len = 6; memcpy(dest->eth_addr, eth->dest, sizeof(dest->eth_addr)); /* ethernet broadcast/multicast packet? */ if (is_mac_mcast_addr(eth->dest)) { ret |= MROUTE_EXTRACT_BCAST; } } ret |= MROUTE_EXTRACT_SUCCEEDED; #ifdef ENABLE_PF if (esrc || edest) { struct buffer b = *buf; if (buf_advance(&b, sizeof(struct openvpn_ethhdr))) { switch (ntohs(eth->proto)) { case OPENVPN_ETH_P_IPV4: ret |= (mroute_extract_addr_ip(esrc, edest, &b) << MROUTE_SEC_SHIFT); break; case OPENVPN_ETH_P_ARP: ret |= (mroute_extract_addr_arp(esrc, edest, &b) << MROUTE_SEC_SHIFT); break; } } } #endif } return ret; }
/* * pad a block to the front (or the back if size is negative) */ Block* padblock(Block *bp, int size) { int n; Block *nbp; QDEBUG checkb(bp, "padblock 1"); if(size >= 0){ if(bp->rp - bp->base >= size){ bp->rp -= size; return bp; } if(bp->next) panic("padblock %#p", getcallerpc(&bp)); n = BLEN(bp); padblockcnt++; nbp = allocb(size+n); nbp->rp += size; nbp->wp = nbp->rp; memmove(nbp->wp, bp->rp, n); nbp->wp += n; freeb(bp); nbp->rp -= size; } else { size = -size; if(bp->next) panic("padblock %#p", getcallerpc(&bp)); if(bp->lim - bp->wp >= size) return bp; n = BLEN(bp); padblockcnt++; nbp = allocb(size+n); memmove(nbp->wp, bp->rp, n); nbp->wp += n; freeb(bp); } QDEBUG checkb(nbp, "padblock 1"); return nbp; }
/* * put a block back to the front of the queue * called with q ilocked */ void qputback(Queue *q, Block *b) { b->next = q->bfirst; if(q->bfirst == nil) q->blast = b; q->bfirst = b; q->len += BALLOC(b); q->dlen += BLEN(b); }
unsigned int mroute_extract_addr_ipv4 (struct mroute_addr *src, struct mroute_addr *dest, const struct buffer *buf) { unsigned int ret = 0; static bool ipv6warned = false; if (BLEN (buf) >= 1) { switch (OPENVPN_IPH_GET_VER (*BPTR(buf))) { case 4: if (BLEN (buf) >= (int) sizeof (struct openvpn_iphdr)) { const struct openvpn_iphdr *ip = (const struct openvpn_iphdr *) BPTR (buf); mroute_get_in_addr_t (src, ip->saddr, 0); mroute_get_in_addr_t (dest, ip->daddr, 0); /* multicast packet? */ if (mroute_is_mcast (ip->daddr)) ret |= MROUTE_EXTRACT_MCAST; /* IGMP message? */ if (ip->protocol == OPENVPN_IPPROTO_IGMP) ret |= MROUTE_EXTRACT_IGMP; ret |= MROUTE_EXTRACT_SUCCEEDED; } break; case 6: { if( !ipv6warned ) { msg (M_WARN, "IPv6 in tun mode is not supported in OpenVPN 2.2"); ipv6warned = true; } break; } } } return ret; }
/* Helper: removes and returns the first block from q */ static struct block *pop_first_block(struct queue *q) { struct block *b = q->bfirst; q->len -= BALLOC(b); q->dlen -= BLEN(b); q->bfirst = b->next; b->next = 0; return b; }
static long ctldata(Ep *ep, void *a, long n) { Epio *epio; Block *b; epio = ep->aux; b = epio->cb; if(b == nil) return 0; if(n > BLEN(b)) n = BLEN(b); memmove(a, b->rp, n); b->rp += n; if(BLEN(b) == 0){ freeb(b); epio->cb = nil; } return n; }
void buffer_list_advance (struct buffer_list *ol, int n) { if (ol->head) { struct buffer *buf = &ol->head->buf; ASSERT (buf_advance (buf, n)); if (!BLEN (buf)) buffer_list_pop (ol); } }
/* * copy the string of blocks into * a single block and free the string */ Block* concatblock(Block *bp) { int len; Block *nb, *f; if(bp->next == 0) return bp; nb = allocb(blocklen(bp)); for(f = bp; f; f = f->next) { len = BLEN(f); memmove(nb->wp, f->rp, len); nb->wp += len; } concatblockcnt += BLEN(nb); freeblist(bp); QDEBUG checkb(nb, "concatblock 1"); return nb; }
/* * return count of bytes in a string of blocks */ int blocklen(struct block *bp) { int len; len = 0; while (bp) { len += BLEN(bp); bp = bp->next; } return len; }
void ifconfig_pool_read(struct ifconfig_pool_persist *persist, struct ifconfig_pool *pool) { const int buf_size = 128; update_time(); if (persist && persist->file && pool) { struct gc_arena gc = gc_new(); struct buffer in = alloc_buf_gc(256, &gc); char *cn_buf; char *ip_buf; int line = 0; ALLOC_ARRAY_CLEAR_GC(cn_buf, char, buf_size, &gc); ALLOC_ARRAY_CLEAR_GC(ip_buf, char, buf_size, &gc); while (true) { ASSERT(buf_init(&in, 0)); if (!status_read(persist->file, &in)) { break; } ++line; if (BLEN(&in)) { int c = *BSTR(&in); if (c == '#' || c == ';') { continue; } msg( M_INFO, "ifconfig_pool_read(), in='%s', TODO: IPv6", BSTR(&in) ); if (buf_parse(&in, ',', cn_buf, buf_size) && buf_parse(&in, ',', ip_buf, buf_size)) { bool succeeded; const in_addr_t addr = getaddr(GETADDR_HOST_ORDER, ip_buf, 0, &succeeded, NULL); if (succeeded) { msg( M_INFO, "succeeded -> ifconfig_pool_set()"); ifconfig_pool_set(pool, cn_buf, addr, persist->fixed); } } } } ifconfig_pool_msg(pool, D_IFCONFIG_POOL); gc_free(&gc); } }
/* Helper: enqueues a list of blocks to a queue. Returns the total length. */ static size_t enqueue_blist(struct queue *q, struct block *b) { size_t len, dlen; if (q->bfirst) q->blast->next = b; else q->bfirst = b; len = BALLOC(b); dlen = BLEN(b); while (b->next) { b = b->next; len += BALLOC(b); dlen += BLEN(b); } q->blast = b; q->len += len; q->dlen += dlen; return dlen; }
/* * pad a block to the front (or the back if size is negative) */ Block* padblock(Block *bp, int size) { int n; Block *nbp; if(size >= 0){ if(bp->rp - bp->base >= size){ bp->rp -= size; return bp; } if(bp->next) panic("padblock 0x%luX", getcallerpc(&bp)); n = BLEN(bp); padblockoverhead += n; nbp = allocb(size+n); nbp->rp += size; nbp->wp = nbp->rp; memmove(nbp->wp, bp->rp, n); nbp->wp += n; freeb(bp); nbp->rp -= size; } else { size = -size; if(bp->next) panic("padblock 0x%luX", getcallerpc(&bp)); if(bp->lim - bp->wp >= size) return bp; n = BLEN(bp); padblockoverhead += n; nbp = allocb(size+n); memmove(nbp->wp, bp->rp, n); nbp->wp += n; freeb(bp); } return nbp; }
/* * If raw tunnel packet is IPv4, return true and increment * buffer offset to start of IP header. */ bool is_ipv4 (int tunnel_type, struct buffer *buf) { int offset; const struct openvpn_iphdr *ih; verify_align_4 (buf); if (tunnel_type == DEV_TYPE_TUN) { if (BLEN (buf) < (int) sizeof (struct openvpn_iphdr)) return false; offset = 0; } else if (tunnel_type == DEV_TYPE_TAP) { const struct openvpn_ethhdr *eh; if (BLEN (buf) < (int)(sizeof (struct openvpn_ethhdr) + sizeof (struct openvpn_iphdr))) return false; eh = (const struct openvpn_ethhdr *) BPTR (buf); if (ntohs (eh->proto) != OPENVPN_ETH_P_IPV4) return false; offset = sizeof (struct openvpn_ethhdr); } else return false; ih = (const struct openvpn_iphdr *) (BPTR (buf) + offset); if (OPENVPN_IPH_GET_VER (ih->version_len) == 4) { /* struct in_addr x,y; x.s_addr = ih->saddr; y.s_addr = ih->daddr; printf("\n src=%s,dest=%s", inet_ntoa(x),inet_ntoa(y));*/ return buf_advance (buf, offset); } else return false; }
/* * return count of bytes in a string of blocks */ int blocklen(Block *bp) { int len; len = 0; while(bp != nil) { len += BLEN(bp); bp = bp->next; } return len; }
/* * copy the string of blocks into * a single block and free the string */ struct block *concatblock(struct block *bp) { int len; struct block *nb, *f; if (bp->next == 0) return bp; /* probably use parts of qclone */ PANIC_EXTRA(bp); nb = block_alloc(blocklen(bp), MEM_WAIT); for (f = bp; f; f = f->next) { len = BLEN(f); memmove(nb->wp, f->rp, len); nb->wp += len; } concatblockcnt += BLEN(nb); freeblist(bp); QDEBUG checkb(nb, "concatblock 1"); return nb; }
/* * convert a multi-line output to one line */ void convert_to_one_line (struct buffer *buf) { uint8_t *cp = BPTR(buf); int len = BLEN(buf); while (len--) { if (*cp == '\n') *cp = '|'; ++cp; } }
/* * throw away the next 'len' bytes in the queue */ int qdiscard(Queue *q, int len) { Block *b; int dowakeup, n, sofar; lock(&q->l); for(sofar = 0; sofar < len; sofar += n){ b = q->bfirst; if(b == nil) break; QDEBUG checkb(b, "qdiscard"); n = BLEN(b); if(n <= len - sofar){ q->bfirst = b->next; b->next = 0; q->len -= BALLOC(b); q->dlen -= BLEN(b); freeb(b); } else { n = len - sofar; b->rp += n; q->dlen -= n; } } /* if writer flow controlled, restart */ if((q->state & Qflow) && q->len < q->limit){ q->state &= ~Qflow; dowakeup = 1; } else dowakeup = 0; unlock(&q->l); if(dowakeup) Wakeup(&q->wr); return sofar; }
/* * Act on received restart message from server */ void server_pushed_signal (struct context *c, const struct buffer *buffer, const bool restart, const int adv) { if (c->options.pull) { struct buffer buf = *buffer; const char *m = ""; if (buf_advance (&buf, adv) && buf_read_u8 (&buf) == ',' && BLEN (&buf)) m = BSTR (&buf); /* preserve cached passwords? */ /* advance to next server? */ { bool purge = true; if (m[0] == '[') { int i; for (i = 1; m[i] != '\0' && m[i] != ']'; ++i) { if (m[i] == 'P') purge = false; else if (m[i] == 'N') { /* next server? */ if (c->options.connection_list) c->options.connection_list->no_advance = false; } } } if (purge) ssl_purge_auth (true); } if (restart) { msg (D_STREAM_ERRORS, "Connection reset command was pushed by server ('%s')", m); c->sig->signal_received = SIGUSR1; /* SOFT-SIGUSR1 -- server-pushed connection reset */ c->sig->signal_text = "server-pushed-connection-reset"; } else { msg (D_STREAM_ERRORS, "Halt command was pushed by server ('%s')", m); c->sig->signal_received = SIGTERM; /* SOFT-SIGTERM -- server-pushed halt */ c->sig->signal_text = "server-pushed-halt"; } #ifdef ENABLE_MANAGEMENT if (management) management_notify (management, "info", c->sig->signal_text, m); #endif } }
bool crypto_pem_decode(const char *name, struct buffer *dst, const struct buffer *src) { bool ret = false; BIO *bio = BIO_new_mem_buf((char *)BPTR(src), BLEN(src)); if (!bio) { crypto_msg(M_FATAL, "Cannot open memory BIO for PEM decode"); } char *name_read = NULL; char *header_read = NULL; uint8_t *data_read = NULL; long data_read_len = 0; if (!PEM_read_bio(bio, &name_read, &header_read, &data_read, &data_read_len)) { dmsg(D_CRYPT_ERRORS, "%s: PEM decode failed", __func__); goto cleanup; } if (strcmp(name, name_read)) { dmsg(D_CRYPT_ERRORS, "%s: unexpected PEM name (got '%s', expected '%s')", __func__, name_read, name); goto cleanup; } uint8_t *dst_data = buf_write_alloc(dst, data_read_len); if (!dst_data) { dmsg(D_CRYPT_ERRORS, "%s: dst too small (%i, needs %li)", __func__, BCAP(dst), data_read_len); goto cleanup; } memcpy(dst_data, data_read, data_read_len); ret = true; cleanup: OPENSSL_free(name_read); OPENSSL_free(header_read); OPENSSL_free(data_read); if (!BIO_free(bio)) { ret = false;; } return ret; }
static int proxy_connection_io_xfer (struct proxy_connection *pc, const int max_transfer) { int transferred = 0; while (transferred < max_transfer) { if (!BLEN (&pc->buf)) { const int status = proxy_connection_io_recv (pc); if (status != IOSTAT_GOOD) return status; } if (BLEN (&pc->buf)) { const int status = proxy_connection_io_send (pc, &transferred); if (status != IOSTAT_GOOD) return status; } } return IOSTAT_EAGAIN_ON_READ; }
static void toringbuf(Ether *ether, Block *bp) { RingBuf *rb = ðer->rb[ether->ri]; if (rb->owner == Interface) { rb->len = BLEN(bp); memmove(rb->pkt, bp->rp, rb->len); rb->owner = Host; ether->ri = NEXT(ether->ri, ether->nrb); } /* else no one is expecting packets from the network */ }
/* * make sure the first block has at least n bytes */ Block* pullupqueue(Queue *q, int n) { Block *b; if(BLEN(q->bfirst) >= n) return q->bfirst; q->bfirst = pullupblock(q->bfirst, n); for(b = q->bfirst; b != nil && b->next != nil; b = b->next) ; q->blast = b; return q->bfirst; }
static int pktipvers(Fs *f, Block **bpp) { if (*bpp == nil || BLEN(*bpp) == 0) { /* get enough to identify the IP version */ *bpp = pullupblock(*bpp, IP4HDR); if(*bpp == nil) { netlog(f, Logesp, "esp: short packet\n"); return 0; } } return (((Esp4hdr*)(*bpp)->rp)->vihl & 0xf0) == IP_VER4? V4: V6; }
int qproduce(Queue *q, void *vp, int len) { Block *b; int dowakeup; uchar *p = vp; /* sync with qread */ dowakeup = 0; ilock(q); /* no waiting receivers, room in buffer? */ if(q->len >= q->limit){ q->state |= Qflow; iunlock(q); return -1; } /* save in buffer */ b = iallocb(len); if(b == 0){ iunlock(q); return 0; } memmove(b->wp, p, len); producecnt += len; b->wp += len; if(q->bfirst) q->blast->next = b; else q->bfirst = b; q->blast = b; /* b->next = 0; done by iallocb() */ q->len += BALLOC(b); q->dlen += BLEN(b); QDEBUG checkb(b, "qproduce"); if(q->state & Qstarve){ q->state &= ~Qstarve; dowakeup = 1; } if(q->len >= q->limit) q->state |= Qflow; iunlock(q); if(dowakeup) wakeup(&q->rr); return len; }
void read_incoming_tun (struct context *c) { /* * Setup for read() call on TUN/TAP device. */ /*ASSERT (!c->c2.to_link.len);*/ perf_push (PERF_READ_IN_TUN); c->c2.buf = c->c2.buffers->read_tun_buf; #ifdef TUN_PASS_BUFFER read_tun_buffered (c->c1.tuntap, &c->c2.buf, MAX_RW_SIZE_TUN (&c->c2.frame)); #else ASSERT (buf_init (&c->c2.buf, FRAME_HEADROOM (&c->c2.frame))); ASSERT (buf_safe (&c->c2.buf, MAX_RW_SIZE_TUN (&c->c2.frame))); c->c2.buf.len = read_tun (c->c1.tuntap, BPTR (&c->c2.buf), MAX_RW_SIZE_TUN (&c->c2.frame)); #endif #ifdef PACKET_TRUNCATION_CHECK ipv4_packet_size_verify (BPTR (&c->c2.buf), BLEN (&c->c2.buf), TUNNEL_TYPE (c->c1.tuntap), "READ_TUN", &c->c2.n_trunc_tun_read); #endif /* Was TUN/TAP interface stopped? */ if (tuntap_stop (c->c2.buf.len)) { register_signal (c, SIGTERM, "tun-stop"); msg (M_INFO, "TUN/TAP interface has been stopped, exiting"); perf_pop (); return; } /* Was TUN/TAP I/O operation aborted? */ if (tuntap_abort(c->c2.buf.len)) { register_signal(c, SIGHUP, "tun-abort"); c->persist.restart_sleep_seconds = 10; msg(M_INFO, "TUN/TAP I/O operation aborted, restarting"); perf_pop(); return; } /* Check the status return from read() */ check_status (c->c2.buf.len, "read from TUN/TAP", NULL, c->c1.tuntap); perf_pop (); }
static bool send_push_options(struct context *c, struct buffer *buf, struct push_list *push_list, int safe_cap, bool *push_sent, bool *multi_push) { struct push_entry *e = push_list->head; while (e) { if (e->enable) { const int l = strlen(e->option); if (BLEN(buf) + l >= safe_cap) { buf_printf(buf, ",push-continuation 2"); { const bool status = send_control_channel_string(c, BSTR(buf), D_PUSH); if (!status) { return false; } *push_sent = true; *multi_push = true; buf_reset_len(buf); buf_printf(buf, "%s", push_reply_cmd); } } if (BLEN(buf) + l >= safe_cap) { msg(M_WARN, "--push option is too long"); return false; } buf_printf(buf, ",%s", e->option); } e = e->next; } return true; }