/** * Described in header. */ char* path_dirname(const char *path) { char *pos; pos = path ? strrchr(path, DIRECTORY_SEPARATOR[0]) : NULL; if (pos && !pos[1]) { /* if path ends with slashes we have to look beyond them */ while (pos > path && *pos == DIRECTORY_SEPARATOR[0]) { /* skip trailing slashes */ pos--; } pos = memrchr(path, DIRECTORY_SEPARATOR[0], pos - path + 1); } if (!pos) { #ifdef WIN32 if (path && strlen(path)) { if ((isalpha(path[0]) && path[1] == ':')) { /* if just a drive letter given, return that as dirname */ return chunk_clone(chunk_from_chars(path[0], ':', 0)).ptr; } } #endif return strdup("."); } while (pos > path && *pos == DIRECTORY_SEPARATOR[0]) { /* skip superfluous slashes */ pos--; } return strndup(path, pos - path + 1); }
/** * load the credential from a blob */ static void *load_from_blob(chunk_t blob, credential_type_t type, int subtype, chunk_t(*cb)(void*,int), void *cb_data, x509_flag_t flags) { void *cred = NULL; bool pgp = FALSE; blob = chunk_clone(blob); if (!is_asn1(blob)) { if (pem_to_bin(&blob, cb, cb_data, &pgp) != SUCCESS) { chunk_clear(&blob); return NULL; } if (pgp && type == CRED_PRIVATE_KEY) { /* PGP encoded keys are parsed with a KEY_ANY key type, as it * can contain any type of key. However, ipsec.secrets uses * RSA for PGP keys, which is actually wrong. */ subtype = KEY_ANY; } } /* if CERT_ANY is given, ASN1 encoded blob is handled as X509 */ if (type == CRED_CERTIFICATE && subtype == CERT_ANY) { subtype = pgp ? CERT_GPG : CERT_X509; } cred = lib->creds->create(lib->creds, type, subtype, pgp ? BUILD_BLOB_PGP : BUILD_BLOB_ASN1_DER, blob, flags ? BUILD_X509_FLAG : BUILD_END, flags, BUILD_END); chunk_clear(&blob); return cred; }
/** * Callback function to prompt for private key passwords */ CALLBACK(password_cb, shared_key_t*, char *prompt, shared_key_type_t type, identification_t *me, identification_t *other, id_match_t *match_me, id_match_t *match_other) { char *pwd; if (type != SHARED_PRIVATE_KEY_PASS) { return NULL; } pwd = getpass(prompt); if (!pwd || strlen(pwd) == 0) { return NULL; } if (match_me) { *match_me = ID_MATCH_PERFECT; } if (match_other) { *match_other = ID_MATCH_PERFECT; } return shared_key_create(type, chunk_clone(chunk_from_str(pwd))); }
/** * Read input data as chunk */ static chunk_t read_from_stream(FILE *stream) { char buf[8096]; size_t len, total = 0; while (TRUE) { len = fread(buf + total, 1, sizeof(buf) - total, stream); if (len < (sizeof(buf) - total)) { if (ferror(stream)) { return chunk_empty; } if (feof(stream)) { return chunk_clone(chunk_create(buf, total + len)); } } total += len; if (total == sizeof(buf)) { fprintf(stderr, "buffer too small to read input!\n"); return chunk_empty; } } }
END_TEST /******************************************************************************* * chunk_create_cat */ START_TEST(test_chunk_create_cat) { chunk_t foo, bar; chunk_t a, b, c; u_char *ptra, *ptrb; foo = chunk_from_str("foo"); bar = chunk_from_str("bar"); /* to simplify things we use the chunk_cata macro */ a = chunk_empty; b = chunk_empty; c = chunk_cata("cc", a, b); ck_assert_int_eq(c.len, 0); ck_assert(c.ptr != NULL); a = foo; b = bar; c = chunk_cata("cc", a, b); ck_assert_int_eq(c.len, 6); ck_assert(chunk_equals(c, chunk_from_str("foobar"))); a = chunk_clone(foo); b = chunk_clone(bar); c = chunk_cata("mm", a, b); ck_assert_int_eq(c.len, 6); ck_assert(chunk_equals(c, chunk_from_str("foobar"))); a = chunk_clone(foo); b = chunk_clone(bar); ptra = a.ptr; ptrb = b.ptr; c = chunk_cata("ss", a, b); ck_assert_int_eq(c.len, 6); ck_assert(chunk_equals(c, chunk_from_str("foobar"))); /* check memory area of cleared chunk */ ck_assert(!chunk_equals(foo, chunk_create(ptra, 3))); ck_assert(!chunk_equals(bar, chunk_create(ptrb, 3))); }
static void echo_inbound(void *user, u_int id, chunk_t buf) { test_data_t *data = user; ck_assert_int_eq(data->id, id); /* count number of bytes, including the header */ data->bytes += buf.len + sizeof(uint32_t); /* echo back data chunk */ data->s->send(data->s, id, chunk_clone(buf)); }
/* decode of RSA pubkey chunk * - format specified in RFC 2537 RSA/MD5 Keys and SIGs in the DNS * - exponent length in bytes (1 or 3 octets) * + 1 byte if in [1, 255] * + otherwise 0x00 followed by 2 bytes of length * - exponent * - modulus */ err_t unpack_RSA_public_key(struct RSA_public_key *rsa, const chunk_t *pubkey) { chunk_t exponent; chunk_t mod; rsa->keyid[0] = '\0'; /* in case of keybolbtoid failure */ if (pubkey->len < 3) return "RSA public key blob way to short"; /* not even room for length! */ rsa->key_rfc3110 = chunk_clone(*pubkey, "rfc3110 format of public key"); if (pubkey->ptr[0] != 0x00) { setchunk(exponent, pubkey->ptr + 1, pubkey->ptr[0]); } else { setchunk(exponent, pubkey->ptr + 3 , (pubkey->ptr[1] << BITS_PER_BYTE) + pubkey->ptr[2]); } if (pubkey->len - (exponent.ptr - pubkey->ptr) < exponent.len + RSA_MIN_OCTETS_RFC) return "RSA public key blob too short"; mod.ptr = exponent.ptr + exponent.len; mod.len = &pubkey->ptr[pubkey->len] - mod.ptr; if (mod.len < RSA_MIN_OCTETS) return RSA_MIN_OCTETS_UGH; if (mod.len > RSA_MAX_OCTETS) return RSA_MAX_OCTETS_UGH; if (mod.len > pubkey->ptr + pubkey->len - mod.ptr) return "RSA public key blob too short"; n_to_mpz(&rsa->e, exponent.ptr, exponent.len); n_to_mpz(&rsa->n, mod.ptr, mod.len); keyblobtoid(pubkey->ptr, pubkey->len, rsa->keyid, sizeof(rsa->keyid)); rsa->k = mpz_sizeinbase(&rsa->n, 2); /* size in bits, for a start */ rsa->k = (rsa->k + BITS_PER_BYTE - 1) / BITS_PER_BYTE; /* now octets */ if (rsa->k != mod.len) { mpz_clear(&rsa->e); mpz_clear(&rsa->n); return "RSA modulus shorter than specified"; } return NULL; }
END_TEST START_TEST(test_create_own) { chunk_t data = chunk_from_str("foobar"); bio_reader_t *reader; data = chunk_clone(data); reader = bio_reader_create_own(data); reader->destroy(reader); }
/** * create a signed pkcs7 contentInfo object */ chunk_t pkcs7_build_signedData(chunk_t data, chunk_t attributes, certificate_t *cert, int digest_alg, private_key_t *key) { contentInfo_t pkcs7Data, signedData; chunk_t authenticatedAttributes = chunk_empty; chunk_t encryptedDigest = chunk_empty; chunk_t signerInfo, cInfo, signature, encoding = chunk_empty;; signature_scheme_t scheme = signature_scheme_from_oid(digest_alg); if (attributes.ptr) { if (key->sign(key, scheme, attributes, &signature)) { encryptedDigest = asn1_wrap(ASN1_OCTET_STRING, "m", signature); authenticatedAttributes = chunk_clone(attributes); *authenticatedAttributes.ptr = ASN1_CONTEXT_C_0; } } else if (data.ptr) { if (key->sign(key, scheme, data, &signature)) { encryptedDigest = asn1_wrap(ASN1_OCTET_STRING, "m", signature); } } signerInfo = asn1_wrap(ASN1_SEQUENCE, "cmmmmm" , ASN1_INTEGER_1 , pkcs7_build_issuerAndSerialNumber(cert) , asn1_algorithmIdentifier(digest_alg) , authenticatedAttributes , asn1_algorithmIdentifier(OID_RSA_ENCRYPTION) , encryptedDigest); pkcs7Data.type = OID_PKCS7_DATA; pkcs7Data.content = (data.ptr == NULL)? chunk_empty : asn1_simple_object(ASN1_OCTET_STRING, data); cert->get_encoding(cert, CERT_ASN1_DER, &encoding); signedData.type = OID_PKCS7_SIGNED_DATA; signedData.content = asn1_wrap(ASN1_SEQUENCE, "cmmmm" , ASN1_INTEGER_1 , asn1_wrap(ASN1_SET, "m", asn1_algorithmIdentifier(digest_alg)) , pkcs7_build_contentInfo(&pkcs7Data) , asn1_wrap(ASN1_CONTEXT_C_0, "m", encoding) , asn1_wrap(ASN1_SET, "m", signerInfo)); cInfo = pkcs7_build_contentInfo(&signedData); DBG3(DBG_LIB, "signedData %B", &cInfo); free(pkcs7Data.content.ptr); free(signedData.content.ptr); return cInfo; }
/** * read the last serial number from file */ static chunk_t read_serial(void) { chunk_t hex, serial = chunk_empty; char one[] = {0x01}; FILE *fd; fd = fopen(OPENAC_SERIAL, "r"); if (fd) { hex = chunk_alloca(64); hex.len = fread(hex.ptr, 1, hex.len, fd); if (hex.len) { /* remove any terminating newline character */ if (hex.ptr[hex.len-1] == '\n') { hex.len--; } serial = chunk_alloca((hex.len / 2) + (hex.len % 2)); serial = chunk_from_hex(hex, serial.ptr); } fclose(fd); } else { DBG1(DBG_LIB, " file '%s' does not exist yet - serial number " "set to 01", OPENAC_SERIAL); } if (!serial.len) { return chunk_clone(chunk_create(one, 1)); } if (chunk_increment(serial)) { /* overflow, prepend 0x01 */ return chunk_cat("cc", chunk_create(one, 1), serial); } return chunk_clone(serial); }
END_TEST /******************************************************************************* * test constructors */ START_TEST(test_create) { chunk_t data = chunk_from_str("foobar"); bio_reader_t *reader; data = chunk_clone(data); reader = bio_reader_create(data); reader->destroy(reader); chunk_free(&data); }
/* Read chunk from file. Return null pointer if fail. */ chunk_ptr chunk_read_legacy(int fd, bool *eofp) { unsigned char buf[CHUNK_MAX_SIZE]; /* Must get enough bytes to read chunk length */ size_t cnt = 0; size_t need_cnt = sizeof(chunk_t); while (cnt < need_cnt) { ssize_t n = read(fd, &buf[cnt], need_cnt-cnt); if (n < 0) { chunk_error("Failed read", NULL); if (eofp) *eofp = false; return NULL; } if (n == 0) { if (eofp) *eofp = true; else chunk_error("Unexpected EOF", NULL); return NULL; } cnt += n; } chunk_ptr creadp = (chunk_ptr) buf; size_t len = creadp->length; if (len > 1) { need_cnt += WORD_BYTES * (len - 1); while (cnt < need_cnt) { ssize_t n = read(fd, &buf[cnt], need_cnt-cnt); if (n < 0) { chunk_error("Failed read", NULL); if (eofp) *eofp = false; return NULL; } cnt += n; } } if (eofp) *eofp = false; return chunk_clone(creadp); }
END_TEST /******************************************************************************* * integer */ START_TEST(test_asn1_integer) { typedef struct { chunk_t b; chunk_t c; } testdata_t; chunk_t b0 = chunk_from_chars(0x02, 0x01, 0x00); chunk_t b1 = chunk_from_chars(0x02, 0x01, 0x7f); chunk_t b2 = chunk_from_chars(0x02, 0x02, 0x00, 0x80); chunk_t c0 = chunk_empty; chunk_t c1 = chunk_from_chars(0x7f); chunk_t c2 = chunk_from_chars(0x80); chunk_t c3 = chunk_from_chars(0x00, 0x80); testdata_t test[] = { { b0, c0 }, { b1, c1 }, { b2, c2 }, { b2, c3 } }; chunk_t a = chunk_empty; int i; for (i = 0; i < countof(test); i++) { a = asn1_integer("c", test[i].c); ck_assert(chunk_equals(a, test[i].b)); chunk_free(&a); a = asn1_integer("m", chunk_clone(test[i].c)); ck_assert(chunk_equals(a, test[i].b)); chunk_free(&a); } }
/* * Defined in header. */ chunk_t asn1_oid_from_string(char *str) { enumerator_t *enumerator; u_char buf[64]; char *end; int i = 0, pos = 0, shift; u_int val, shifted_val, first = 0; enumerator = enumerator_create_token(str, ".", ""); while (enumerator->enumerate(enumerator, &str)) { val = strtoul(str, &end, 10); if (end == str || pos > countof(buf)) { pos = 0; break; } switch (i++) { case 0: first = val; break; case 1: buf[pos++] = first * 40 + val; break; default: shift = 28; /* sufficient to handle 32 bit node numbers */ while (shift) { shifted_val = val >> shift; shift -= 7; if (shifted_val) /* do not encode leading zeroes */ { buf[pos++] = 0x80 | (shifted_val & 0x7F); } } buf[pos++] = val & 0x7F; } } enumerator->destroy(enumerator); return chunk_clone(chunk_create(buf, pos)); }
END_TEST /******************************************************************************* * bitstring */ START_TEST(test_asn1_bitstring) { chunk_t a = chunk_empty; chunk_t b = chunk_from_chars(0x03, 0x05, 0x00, 0xa1, 0xa2, 0xa3, 0xa4); chunk_t c = chunk_from_chars(0xa1, 0xa2, 0xa3, 0xa4); chunk_t d = chunk_clone(c); a = asn1_bitstring("c", c); ck_assert(chunk_equals(a, b)); chunk_free(&a); a = asn1_bitstring("m", d); ck_assert(chunk_equals(a, b)); chunk_free(&a); }
// Return a link, an image, or a literal close bracket. static cmark_node *handle_close_bracket(subject *subj) { bufsize_t initial_pos, after_link_text_pos; bufsize_t endurl, starttitle, endtitle, endall; bufsize_t sps, n; cmark_reference *ref = NULL; cmark_chunk url_chunk, title_chunk; cmark_chunk url, title; bracket *opener; cmark_node *inl; cmark_chunk raw_label; int found_label; cmark_node *tmp, *tmpnext; bool is_image; advance(subj); // advance past ] initial_pos = subj->pos; // get last [ or ![ opener = subj->last_bracket; if (opener == NULL) { return make_str(subj->mem, cmark_chunk_literal("]")); } if (!opener->active) { // take delimiter off stack pop_bracket(subj); return make_str(subj->mem, cmark_chunk_literal("]")); } // If we got here, we matched a potential link/image text. // Now we check to see if it's a link/image. is_image = opener->image; after_link_text_pos = subj->pos; // First, look for an inline link. if (peek_char(subj) == '(' && ((sps = scan_spacechars(&subj->input, subj->pos + 1)) > -1) && ((n = manual_scan_link_url(&subj->input, subj->pos + 1 + sps, &url_chunk)) > -1)) { // try to parse an explicit link: endurl = subj->pos + 1 + sps + n; starttitle = endurl + scan_spacechars(&subj->input, endurl); // ensure there are spaces btw url and title endtitle = (starttitle == endurl) ? starttitle : starttitle + scan_link_title(&subj->input, starttitle); endall = endtitle + scan_spacechars(&subj->input, endtitle); if (peek_at(subj, endall) == ')') { subj->pos = endall + 1; title_chunk = cmark_chunk_dup(&subj->input, starttitle, endtitle - starttitle); url = cmark_clean_url(subj->mem, &url_chunk); title = cmark_clean_title(subj->mem, &title_chunk); cmark_chunk_free(subj->mem, &url_chunk); cmark_chunk_free(subj->mem, &title_chunk); goto match; } else { // it could still be a shortcut reference link subj->pos = after_link_text_pos; } } // Next, look for a following [link label] that matches in refmap. // skip spaces raw_label = cmark_chunk_literal(""); found_label = link_label(subj, &raw_label); if (!found_label) { // If we have a shortcut reference link, back up // to before the spacse we skipped. subj->pos = initial_pos; } if ((!found_label || raw_label.len == 0) && !opener->bracket_after) { cmark_chunk_free(subj->mem, &raw_label); raw_label = cmark_chunk_dup(&subj->input, opener->position, initial_pos - opener->position - 1); found_label = true; } if (found_label) { ref = cmark_reference_lookup(subj->refmap, &raw_label); cmark_chunk_free(subj->mem, &raw_label); } if (ref != NULL) { // found url = chunk_clone(subj->mem, &ref->url); title = chunk_clone(subj->mem, &ref->title); goto match; } else { goto noMatch; } noMatch: // If we fall through to here, it means we didn't match a link: pop_bracket(subj); // remove this opener from delimiter list subj->pos = initial_pos; return make_str(subj->mem, cmark_chunk_literal("]")); match: inl = make_simple(subj->mem, is_image ? CMARK_NODE_IMAGE : CMARK_NODE_LINK); inl->as.link.url = url; inl->as.link.title = title; cmark_node_insert_before(opener->inl_text, inl); // Add link text: tmp = opener->inl_text->next; while (tmp) { tmpnext = tmp->next; cmark_node_append_child(inl, tmp); tmp = tmpnext; } // Free the bracket [: cmark_node_free(opener->inl_text); process_emphasis(subj, opener->previous_delimiter); pop_bracket(subj); // Now, if we have a link, we also want to deactivate earlier link // delimiters. (This code can be removed if we decide to allow links // inside links.) if (!is_image) { opener = subj->last_bracket; while (opener != NULL) { if (!opener->image) { if (!opener->active) { break; } else { opener->active = false; } } opener = opener->previous; } } return NULL; }
/** * Determine the type of the attribute and its value */ static bool parse_attributes(char *name, char *value, value_type_t *value_type, configuration_attribute_type_t *type, configuration_attribute_type_t *type_ip6, chunk_t *blob) { host_t *addr = NULL, *mask = NULL; chunk_t addr_chunk, mask_chunk, blob_next; char *text = "", *pos_addr, *pos_mask, *pos_next, *endptr; int i; switch (*value_type) { case VALUE_STRING: *blob = chunk_create(value, strlen(value)); *blob = chunk_clone(*blob); break; case VALUE_HEX: *blob = chunk_from_hex(chunk_create(value, strlen(value)), NULL); break; case VALUE_ADDR: addr = host_create_from_string(value, 0); if (addr == NULL) { fprintf(stderr, "invalid IP address: '%s'.\n", value); return FALSE; } addr_chunk = addr->get_address(addr); *blob = chunk_clone(addr_chunk); break; case VALUE_SUBNET: *blob = chunk_empty; pos_next = value; do { pos_addr = pos_next; pos_next = strchr(pos_next, ','); if (pos_next) { *pos_next = '\0'; pos_next += 1; } pos_mask = strchr(pos_addr, '/'); if (pos_mask == NULL) { fprintf(stderr, "invalid IPv4 subnet: '%s'.\n", pos_addr); free(blob->ptr); return FALSE; } *pos_mask = '\0'; pos_mask += 1; addr = host_create_from_string(pos_addr, 0); mask = host_create_from_string(pos_mask, 0); if (addr == NULL || addr->get_family(addr) != AF_INET || mask == NULL || mask->get_family(addr) != AF_INET) { fprintf(stderr, "invalid IPv4 subnet: '%s/%s'.\n", pos_addr, pos_mask); DESTROY_IF(addr); DESTROY_IF(mask); free(blob->ptr); return FALSE; } addr_chunk = addr->get_address(addr); mask_chunk = mask->get_address(mask); blob_next = chunk_alloc(blob->len + UNITY_NETWORK_LEN); memcpy(blob_next.ptr, blob->ptr, blob->len); pos_addr = blob_next.ptr + blob->len; memset(pos_addr, 0x00, UNITY_NETWORK_LEN); memcpy(pos_addr, addr_chunk.ptr, 4); memcpy(pos_addr + 4, mask_chunk.ptr, 4); addr->destroy(addr); addr = NULL; mask->destroy(mask); chunk_free(blob); *blob = blob_next; } while (pos_next); break; case VALUE_NONE: *blob = chunk_empty; break; } /* init the attribute type */ *type = 0; *type_ip6 = 0; for (i = 0; i < countof(attr_info); i++) { if (strcaseeq(name, attr_info[i].keyword)) { *type = attr_info[i].type; *type_ip6 = attr_info[i].type_ip6; if (*value_type == VALUE_NONE) { *value_type = attr_info[i].value_type; return TRUE; } if (*value_type != attr_info[i].value_type && *value_type != VALUE_HEX) { switch (attr_info[i].value_type) { case VALUE_STRING: text = "a string"; break; case VALUE_HEX: text = "a hex"; break; case VALUE_ADDR: text = "an IP address"; break; case VALUE_SUBNET: text = "a subnet"; break; case VALUE_NONE: text = "no"; break; } fprintf(stderr, "the %s attribute requires %s value.\n", name, text); DESTROY_IF(addr); free(blob->ptr); return FALSE; } if (*value_type == VALUE_ADDR) { *type = (addr->get_family(addr) == AF_INET) ? attr_info[i].type : attr_info[i].type_ip6; addr->destroy(addr); } else if (*value_type == VALUE_HEX) { *value_type = attr_info[i].value_type; if (*value_type == VALUE_ADDR) { if (blob->len == 16) { *type = attr_info[i].type_ip6; } else if (blob->len != 4) { fprintf(stderr, "the %s attribute requires " "a valid IP address.\n", name); free(blob->ptr); return FALSE; } } } return TRUE; } } /* clean up */ DESTROY_IF(addr); /* is the attribute type numeric? */ *type = strtol(name, &endptr, 10); if (*endptr != '\0') { fprintf(stderr, "the %s attribute is not recognized.\n", name); free(blob->ptr); return FALSE; } if (*type < 1 || *type > 32767) { fprintf(stderr, "the attribute type must lie in the range 1..32767.\n"); free(blob->ptr); return FALSE; } if (*value_type == VALUE_NONE) { *value_type = VALUE_HEX; } return TRUE; }
chunk_ptr chunk_read(int fd, bool* eofp) { if (fd > maxfd) { // on first call, we zero the buffer set if (maxfd == 0) { FD_ZERO(&buf_set); FD_ZERO(&in_set); } maxfd = fd; } buf_node* curr_node = NULL; buf_node* temp_node = NULL; //create new head if (buf_list_head == NULL) { buf_list_head = calloc_or_fail(sizeof(buf_node), 1, "chunk_read create head"); buf_list_head->fd = fd; #if RPT >= 5 report(5, "created a node for fd %d as head\n", fd); #endif buf_list_head->length = 0; buf_list_head->location = 0; buf_list_head->buf = calloc_or_fail(CHUNK_MAX_SIZE, 2, "chunk_read create head buf"); curr_node = buf_list_head; } // search for the fd in the buffer list, if it exists else { temp_node = buf_list_head; while (temp_node != NULL && curr_node == NULL) { if (fd == temp_node->fd) { curr_node = temp_node; #if RPT >= 5 report(5, "found node for fd %d\n", fd); #endif } temp_node = temp_node->next; } } // if it doesn't exist, create the new fd buffer at the head of the list if (curr_node == NULL) { curr_node = calloc_or_fail(sizeof(buf_node), 1, "chunk_read create node"); curr_node->fd = fd; curr_node->length = 0; curr_node->location = 0; curr_node->next = buf_list_head; curr_node->buf = calloc_or_fail(CHUNK_MAX_SIZE, 2, "chunk_read create head buf"); #if RPT >= 5 report(5, "created a node for fd %d at head\n", fd); #endif buf_list_head = curr_node; } // if we can copy to the beginning, then we copy to the beginning // (if the read point is past the beginning, and if the end of // the buffered data is past the midway point of the buffer) if (curr_node->length + curr_node->location >= CHUNK_MAX_SIZE && curr_node->location > 0) { memmove(curr_node->buf, (char *)(curr_node->buf + curr_node->location), curr_node->length); curr_node->location = 0; } // read if possible - if there is space, if the inset contains it, and if we // want to use buffering (otherwise we don't want random buffer refills) if (((curr_node->length + curr_node->location) < CHUNK_MAX_SIZE) && bufferReadBool && !(!(FD_ISSET(fd, &in_set))) ) { #if RPT >= 5 report(5, "reading for %d\n", curr_node->fd); #endif ssize_t n = read(curr_node->fd, curr_node->buf + curr_node->location + curr_node->length, CHUNK_MAX_SIZE); curr_node->length += n; } #if RPT >= 5 report(5, "about to get header for %d\n", fd); #endif // get header of chunk size_t need_cnt = sizeof(chunk_t); unsigned char buf[CHUNK_MAX_SIZE]; unsigned char* buf_ptr = (unsigned char*)buf; ssize_t n = buf_read(curr_node, eofp, buf_ptr, need_cnt); //ssize_t n = read(curr_node->fd, buf, need_cnt); if (n <= 0) { return NULL; } #if RPT >= 5 report(5, "about to get rest of chunk for fd %d\n", fd); #endif // get rest of chunk chunk_ptr creadp = (chunk_ptr) buf_ptr; size_t len = creadp->length; #if RPT >= 5 report(5, "len needed: %d", len); #endif if (len > 1) { need_cnt = WORD_BYTES * (len - 1); #if RPT >= 5 report(5, "head buf pointer at %p", buf_ptr); #endif buf_ptr = (unsigned char *)(buf_ptr + n); #if RPT >= 5 report(5, "moved pointer to %p for rest", buf_ptr); #endif ssize_t n = buf_read(curr_node, eofp, buf_ptr, need_cnt); //ssize_t n = read(curr_node->fd, buf_ptr, need_cnt); if (n < 0) { chunk_error("Failed read", NULL); if (eofp) *eofp = false; return NULL; } } #if RPT >= 5 report(5, "exiting chunk_read_buffered_builtin!\n"); #endif if (eofp) *eofp = false; return chunk_clone(creadp); }
/** * Add ITA Device ID attribute to the send queue */ static void add_device_id(imc_msg_t *msg) { pa_tnc_attr_t *attr; chunk_t value = chunk_empty, keyid; char *name, *device_id, *cert_path; certificate_t *cert = NULL; public_key_t *pubkey; /* Get the device ID as a character string */ device_id = lib->settings->get_str(lib->settings, "%s.plugins.imc-os.device_id", NULL, lib->ns); if (device_id) { value = chunk_clone(chunk_from_str(device_id)); } if (value.len == 0) { /* Derive the device ID from a raw public key */ cert_path = lib->settings->get_str(lib->settings, "%s.plugins.imc-os.device_pubkey", NULL, lib->ns); if (cert_path) { cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_TRUSTED_PUBKEY, BUILD_FROM_FILE, cert_path, BUILD_END); if (cert) { DBG2(DBG_IMC, "loaded device public key from '%s'", cert_path); } else { DBG1(DBG_IMC, "loading device public key from '%s' failed", cert_path); } } if (!cert) { /* Derive the device ID from the public key contained in a certificate */ cert_path = lib->settings->get_str(lib->settings, "%s.plugins.imc-os.device_cert", NULL, lib->ns); if (cert_path) { cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, BUILD_FROM_FILE, cert_path, BUILD_END); if (cert) { DBG2(DBG_IMC, "loaded device certificate from '%s'", cert_path); } else { DBG1(DBG_IMC, "loading device certificate from '%s' failed", cert_path); } } } /* Compute the SHA-1 keyid of the retrieved device public key */ if (cert) { pubkey = cert->get_public_key(cert); if (pubkey) { if (pubkey->get_fingerprint(pubkey, KEYID_PUBKEY_INFO_SHA1, &keyid)) { value = chunk_to_hex(keyid, NULL, FALSE); } pubkey->destroy(pubkey); } cert->destroy(cert); } } if (value.len == 0) { /* Derive the device ID from some unique OS settings */ name = os->get_type(os) == OS_TYPE_ANDROID ? "android_id" : "/var/lib/dbus/machine-id"; value = os->get_setting(os, name); /* Trim trailing newline character */ if (value.len > 0 && value.ptr[value.len - 1] == '\n') { value.len--; } } if (value.len == 0) { DBG1(DBG_IMC, "no device ID available"); return; } DBG1(DBG_IMC, "device ID is %.*s", value.len, value.ptr); attr = ita_attr_device_id_create(value); msg->add_attribute(msg, attr); free(value.ptr); }
bool send_op(chunk_ptr msg) { dword_t dh = chunk_get_dword(msg, 0); unsigned agent = msg_get_dheader_agent(dh); unsigned code = msg_get_dheader_code(dh); if (code == MSG_OPERATION) { agent_stat_counter[STATA_OPERATION_TOTAL]++; if (self_route && agent == own_agent) { agent_stat_counter[STATA_OPERATION_LOCAL]++; #if RPT >= 6 word_t id = msg_get_dheader_op_id(dh); report(6, "Routing operator with id 0x%lx to self", id); #endif receive_operation(chunk_clone(msg)); return true; } } if (code == MSG_OPERAND) { agent_stat_counter[STATA_OPERAND_TOTAL]++; if (self_route && agent == own_agent && !isclient) { agent_stat_counter[STATA_OPERAND_LOCAL]++; #if RPT >= 6 word_t id = msg_get_dheader_op_id(dh); report(6, "Routing operand with id 0x%lx to self", id); #endif receive_operand(chunk_clone(msg)); return true; } } // Try to send to a local router if possible int rfd; if (local_router_fd == -1) { unsigned idx = random() % nrouters; rfd = router_fd_array[idx]; #if RPT >= 5 word_t id = msg_get_dheader_op_id(dh); report(5, "Sending message with id 0x%x through router %u (fd %d)", id, idx, rfd); #endif } else { rfd = local_router_fd; #if RPT >= 5 word_t id = msg_get_dheader_op_id(dh); report(5, "Sending message with id 0x%x through the local router (fd %d)", id, rfd); #endif } bool ok = chunk_write(rfd, msg); if (ok) { #if RPT >= 5 report(5, "Message sent"); #endif } else { err(false, "Failed"); } return ok; }
static bool do_test_mct(test_vector_t *test) { crypter_t *crypter; chunk_t prev, *input, *output; int i, j; crypter = lib->crypto->create_crypter(lib->crypto, ENCR_AES_CBC, test->key.len); if (!crypter) { DBG1(DBG_APP, "algorithm %N or key length (%d bits) not supported", encryption_algorithm_names, ENCR_AES_CBC, test->key.len * 8); return FALSE; } input = ctx.decrypt ? &test->cipher : &test->plain; output = ctx.decrypt ? &test->plain : &test->cipher; if (crypter->get_block_size(crypter) != input->len) { DBG1(DBG_APP, "MCT only works for input with a length of one block"); crypter->destroy(crypter); return FALSE; } prev = chunk_alloca(input->len); /* assume initial IV as previous output */ *output = chunk_clone(test->iv); for (i = 0; i < 100; i++) { if (i > 0) { /* we copied the original lines already */ fprintf(ctx.out, "COUNT = %d\n", i); fprintf(ctx.out, "KEY = %+B\n", &test->key); fprintf(ctx.out, "IV = %+B\n", &test->iv); fprintf(ctx.out, "%s = %+B\n", ctx.decrypt ? "CIPHERTEXT" : "PLAINTEXT", input); } if (!crypter->set_key(crypter, test->key)) { DBG1(DBG_APP, "failed to set key"); return FALSE; } for (j = 0; j < 1000; j++) { /* store previous output as it is used as input after next */ memcpy(prev.ptr, output->ptr, prev.len); chunk_free(output); if (!do_crypt(crypter, test)) { crypter->destroy(crypter); return FALSE; } /* prepare the next IV (our API does not allow incremental calls) */ if (ctx.decrypt) { memcpy(test->iv.ptr, input->ptr, test->iv.len); } else { memcpy(test->iv.ptr, output->ptr, test->iv.len); } /* the previous output is the next input */ memcpy(input->ptr, prev.ptr, input->len); } fprintf(ctx.out, "%s = %+B\n\n", ctx.decrypt ? "PLAINTEXT" : "CIPHERTEXT", output); /* derive key for next round */ switch (test->key.len) { case 16: memxor(test->key.ptr, output->ptr, output->len); break; case 24: memxor(test->key.ptr, prev.ptr + 8, 8); memxor(test->key.ptr + 8, output->ptr, output->len); break; case 32: memxor(test->key.ptr, prev.ptr, prev.len); memxor(test->key.ptr + prev.len, output->ptr, output->len); break; } /* the current output is used as IV for the next round */ memcpy(test->iv.ptr, output->ptr, test->iv.len); } crypter->destroy(crypter); /* we return FALSE as we print the output ourselves */ return FALSE; }
/** * create the lease query using the filter string */ static enumerator_t *create_lease_query(char *filter, array_t **to_free) { enumerator_t *query; chunk_t id_chunk = chunk_empty, addr_chunk = chunk_empty; id_type_t id_type = 0; u_int tstamp = 0; bool online = FALSE, valid = FALSE, expired = FALSE; char *value, *pos, *pool = NULL; enum { FIL_POOL = 0, FIL_ID, FIL_ADDR, FIL_TSTAMP, FIL_STATE, }; char *const token[] = { [FIL_POOL] = "pool", [FIL_ID] = "id", [FIL_ADDR] = "addr", [FIL_TSTAMP] = "tstamp", [FIL_STATE] = "status", NULL }; /* if the filter string contains a distinguished name as a ID, we replace * ", " by "/ " in order to not confuse the getsubopt parser */ pos = filter; while ((pos = strchr(pos, ','))) { if (pos[1] == ' ') { pos[0] = '/'; } pos++; } while (filter && *filter != '\0') { switch (getsubopt(&filter, token, &value)) { case FIL_POOL: if (value) { pool = value; } break; case FIL_ID: if (value) { identification_t *id; id = identification_create_from_string(value); id_type = id->get_type(id); id_chunk = chunk_clone(id->get_encoding(id)); array_insert_create(to_free, ARRAY_TAIL, id_chunk.ptr); id->destroy(id); } break; case FIL_ADDR: if (value) { host_t *addr; addr = host_create_from_string(value, 0); if (!addr) { fprintf(stderr, "invalid 'addr' in filter string.\n"); exit(EXIT_FAILURE); } addr_chunk = chunk_clone(addr->get_address(addr)); array_insert_create(to_free, ARRAY_TAIL, addr_chunk.ptr); addr->destroy(addr); } break; case FIL_TSTAMP: if (value) { tstamp = atoi(value); } if (tstamp == 0) { online = TRUE; } break; case FIL_STATE: if (value) { if (streq(value, "online")) { online = TRUE; } else if (streq(value, "valid")) { valid = TRUE; } else if (streq(value, "expired")) { expired = TRUE; } else { fprintf(stderr, "invalid 'state' in filter string.\n"); exit(EXIT_FAILURE); } } break; default: fprintf(stderr, "invalid filter string.\n"); exit(EXIT_FAILURE); break; } } query = db->query(db, "SELECT name, addresses.address, identities.type, " "identities.data, leases.acquired, leases.released, timeout " "FROM leases JOIN addresses ON leases.address = addresses.id " "JOIN pools ON addresses.pool = pools.id " "JOIN identities ON leases.identity = identities.id " "WHERE (? OR name = ?) " "AND (? OR (identities.type = ? AND identities.data = ?)) " "AND (? OR addresses.address = ?) " "AND (? OR (? >= leases.acquired AND (? <= leases.released))) " "AND (? OR leases.released > ? - timeout) " "AND (? OR leases.released < ? - timeout) " "AND ? " "UNION " "SELECT name, address, identities.type, identities.data, " "acquired, released, timeout FROM addresses " "JOIN pools ON addresses.pool = pools.id " "JOIN identities ON addresses.identity = identities.id " "WHERE ? AND released = 0 " "AND (? OR name = ?) " "AND (? OR (identities.type = ? AND identities.data = ?)) " "AND (? OR address = ?)", DB_INT, pool == NULL, DB_TEXT, pool, DB_INT, !id_chunk.ptr, DB_INT, id_type, DB_BLOB, id_chunk, DB_INT, !addr_chunk.ptr, DB_BLOB, addr_chunk, DB_INT, tstamp == 0, DB_UINT, tstamp, DB_UINT, tstamp, DB_INT, !valid, DB_INT, time(NULL), DB_INT, !expired, DB_INT, time(NULL), DB_INT, !online, /* union */ DB_INT, !(valid || expired), DB_INT, pool == NULL, DB_TEXT, pool, DB_INT, !id_chunk.ptr, DB_INT, id_type, DB_BLOB, id_chunk, DB_INT, !addr_chunk.ptr, DB_BLOB, addr_chunk, /* res */ DB_TEXT, DB_BLOB, DB_INT, DB_BLOB, DB_UINT, DB_UINT, DB_UINT); return query; }
/** * Converts a PEM encoded file into its binary form (RFC 1421, RFC 934) */ static status_t pem_to_bin(chunk_t *blob, bool *pgp) { typedef enum { PEM_PRE = 0, PEM_MSG = 1, PEM_HEADER = 2, PEM_BODY = 3, PEM_POST = 4, PEM_ABORT = 5 } state_t; encryption_algorithm_t alg = ENCR_UNDEFINED; size_t key_size = 0; bool encrypted = FALSE; state_t state = PEM_PRE; chunk_t src = *blob; chunk_t dst = *blob; chunk_t line = chunk_empty; chunk_t iv = chunk_empty; u_char iv_buf[HASH_SIZE_MD5]; status_t status = NOT_FOUND; enumerator_t *enumerator; shared_key_t *shared; dst.len = 0; iv.ptr = iv_buf; iv.len = 0; while (fetchline(&src, &line)) { if (state == PEM_PRE) { if (find_boundary("BEGIN", &line)) { state = PEM_MSG; } continue; } else { if (find_boundary("END", &line)) { state = PEM_POST; break; } if (state == PEM_MSG) { state = PEM_HEADER; if (memchr(line.ptr, ':', line.len) == NULL) { state = PEM_BODY; } } if (state == PEM_HEADER) { err_t ugh = NULL; chunk_t name = chunk_empty; chunk_t value = chunk_empty; /* an empty line separates HEADER and BODY */ if (line.len == 0) { state = PEM_BODY; continue; } /* we are looking for a parameter: value pair */ DBG2(DBG_ASN, " %.*s", (int)line.len, line.ptr); ugh = extract_parameter_value(&name, &value, &line); if (ugh != NULL) { continue; } if (match("Proc-Type", &name) && *value.ptr == '4') { encrypted = TRUE; } else if (match("DEK-Info", &name)) { chunk_t dek; if (!extract_token(&dek, ',', &value)) { dek = value; } if (match("DES-EDE3-CBC", &dek)) { alg = ENCR_3DES; key_size = 24; } else if (match("AES-128-CBC", &dek)) { alg = ENCR_AES_CBC; key_size = 16; } else if (match("AES-192-CBC", &dek)) { alg = ENCR_AES_CBC; key_size = 24; } else if (match("AES-256-CBC", &dek)) { alg = ENCR_AES_CBC; key_size = 32; } else { DBG1(DBG_ASN, " encryption algorithm '%.*s'" " not supported", (int)dek.len, dek.ptr); return NOT_SUPPORTED; } if (!eat_whitespace(&value) || value.len > 2*sizeof(iv_buf)) { return PARSE_ERROR; } iv = chunk_from_hex(value, iv_buf); } } else /* state is PEM_BODY */ { chunk_t data; /* remove any trailing whitespace */ if (!extract_token(&data ,' ', &line)) { data = line; } /* check for PGP armor checksum */ if (*data.ptr == '=') { *pgp = TRUE; data.ptr++; data.len--; DBG2(DBG_ASN, " armor checksum: %.*s", (int)data.len, data.ptr); continue; } if (blob->len - dst.len < data.len / 4 * 3) { state = PEM_ABORT; } data = chunk_from_base64(data, dst.ptr); dst.ptr += data.len; dst.len += data.len; } } } /* set length to size of binary blob */ blob->len = dst.len; if (state != PEM_POST) { DBG1(DBG_LIB, " file coded in unknown format, discarded"); return PARSE_ERROR; } if (!encrypted) { return SUCCESS; } enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr, SHARED_PRIVATE_KEY_PASS, NULL, NULL); while (enumerator->enumerate(enumerator, &shared, NULL, NULL)) { chunk_t passphrase, chunk; passphrase = shared->get_key(shared); chunk = chunk_clone(*blob); status = pem_decrypt(&chunk, alg, key_size, iv, passphrase); if (status == SUCCESS) { memcpy(blob->ptr, chunk.ptr, chunk.len); blob->len = chunk.len; } free(chunk.ptr); if (status != INVALID_ARG) { /* try again only if passphrase invalid */ break; } } enumerator->destroy(enumerator); return status; }
int main(int argc, char *argv[]) { char *address = NULL, *identity = "%any", *secret = NULL; int port = PT_TLS_PORT; init(); while (TRUE) { struct option long_opts[] = { {"help", no_argument, NULL, 'h' }, {"connect", required_argument, NULL, 'c' }, {"client", required_argument, NULL, 'i' }, {"secret", required_argument, NULL, 's' }, {"port", required_argument, NULL, 'p' }, {"cert", required_argument, NULL, 'x' }, {"key", required_argument, NULL, 'k' }, {"mutual", no_argument, NULL, 'm' }, {"quiet", no_argument, NULL, 'q' }, {"debug", required_argument, NULL, 'd' }, {"optionsfrom", required_argument, NULL, '+' }, {0,0,0,0 } }; switch (getopt_long(argc, argv, "", long_opts, NULL)) { case EOF: break; case 'h': /* --help */ usage(stdout); return 0; case 'x': /* --cert <file> */ if (!load_certificate(optarg)) { return 1; } continue; case 'k': /* --key <file> */ if (!load_key(optarg)) { return 1; } continue; case 'c': /* --connect <hostname|address> */ if (address) { usage(stderr); return 1; } address = optarg; continue; case 'i': /* --client <client-id> */ identity = optarg; continue; case 's': /* --secret <password> */ secret = optarg; continue; case 'p': /* --port <port> */ port = atoi(optarg); continue; case 'm': /* --mutual */ lib->settings->set_bool(lib->settings, "%s.plugins.tnccs-20.mutual", TRUE, lib->ns); continue; case 'q': /* --quiet */ log_to_stderr = FALSE; continue; case 'd': /* --debug <level> */ default_loglevel = atoi(optarg); continue; case '+': /* --optionsfrom <filename> */ if (!options->from(options, optarg, &argc, &argv, optind)) { return 1; } continue; default: usage(stderr); return 1; } break; } if (!address) { usage(stderr); return 1; } if (secret) { creds->add_shared(creds, shared_key_create(SHARED_EAP, chunk_clone(chunk_from_str(secret))), identification_create_from_string(identity), NULL); } return client(address, port, identity); }
/** * @brief openac main program * * @param argc number of arguments * @param argv pointer to the argument values */ int main(int argc, char **argv) { certificate_t *attr_cert = NULL; certificate_t *userCert = NULL; certificate_t *signerCert = NULL; private_key_t *signerKey = NULL; time_t notBefore = UNDEFINED_TIME; time_t notAfter = UNDEFINED_TIME; time_t validity = 0; char *keyfile = NULL; char *certfile = NULL; char *usercertfile = NULL; char *outfile = NULL; char *groups = ""; char buf[BUF_LEN]; chunk_t passphrase = { buf, 0 }; chunk_t serial = chunk_empty; chunk_t attr_chunk = chunk_empty; int status = 1; /* enable openac debugging hook */ dbg = openac_dbg; passphrase.ptr[0] = '\0'; openlog("openac", 0, LOG_AUTHPRIV); /* initialize library */ atexit(library_deinit); if (!library_init(NULL)) { exit(SS_RC_LIBSTRONGSWAN_INTEGRITY); } if (lib->integrity && !lib->integrity->check_file(lib->integrity, "openac", argv[0])) { fprintf(stderr, "integrity check of openac failed\n"); exit(SS_RC_DAEMON_INTEGRITY); } if (!lib->plugins->load(lib->plugins, lib->settings->get_str(lib->settings, "openac.load", PLUGINS))) { exit(SS_RC_INITIALIZATION_FAILED); } /* initialize optionsfrom */ options_t *options = options_create(); /* handle arguments */ for (;;) { static const struct option long_opts[] = { /* name, has_arg, flag, val */ { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'v' }, { "optionsfrom", required_argument, NULL, '+' }, { "quiet", no_argument, NULL, 'q' }, { "cert", required_argument, NULL, 'c' }, { "key", required_argument, NULL, 'k' }, { "password", required_argument, NULL, 'p' }, { "usercert", required_argument, NULL, 'u' }, { "groups", required_argument, NULL, 'g' }, { "days", required_argument, NULL, 'D' }, { "hours", required_argument, NULL, 'H' }, { "startdate", required_argument, NULL, 'S' }, { "enddate", required_argument, NULL, 'E' }, { "out", required_argument, NULL, 'o' }, { "debug", required_argument, NULL, 'd' }, { 0,0,0,0 } }; int c = getopt_long(argc, argv, "hv+:qc:k:p;u:g:D:H:S:E:o:d:", long_opts, NULL); /* Note: "breaking" from case terminates loop */ switch (c) { case EOF: /* end of flags */ break; case 0: /* long option already handled */ continue; case ':': /* diagnostic already printed by getopt_long */ case '?': /* diagnostic already printed by getopt_long */ case 'h': /* --help */ usage(NULL); status = 1; goto end; case 'v': /* --version */ printf("openac (strongSwan %s)\n", VERSION); status = 0; goto end; case '+': /* --optionsfrom <filename> */ { char path[BUF_LEN]; if (*optarg == '/') /* absolute pathname */ { strncpy(path, optarg, BUF_LEN); path[BUF_LEN-1] = '\0'; } else /* relative pathname */ { snprintf(path, BUF_LEN, "%s/%s", OPENAC_PATH, optarg); } if (!options->from(options, path, &argc, &argv, optind)) { status = 1; goto end; } } continue; case 'q': /* --quiet */ stderr_quiet = TRUE; continue; case 'c': /* --cert */ certfile = optarg; continue; case 'k': /* --key */ keyfile = optarg; continue; case 'p': /* --key */ if (strlen(optarg) >= BUF_LEN) { usage("passphrase too long"); goto end; } strncpy(passphrase.ptr, optarg, BUF_LEN); passphrase.len = min(strlen(optarg), BUF_LEN); continue; case 'u': /* --usercert */ usercertfile = optarg; continue; case 'g': /* --groups */ groups = optarg; continue; case 'D': /* --days */ if (optarg == NULL || !isdigit(optarg[0])) { usage("missing number of days"); goto end; } else { char *endptr; long days = strtol(optarg, &endptr, 0); if (*endptr != '\0' || endptr == optarg || days <= 0) { usage("<days> must be a positive number"); goto end; } validity += 24*3600*days; } continue; case 'H': /* --hours */ if (optarg == NULL || !isdigit(optarg[0])) { usage("missing number of hours"); goto end; } else { char *endptr; long hours = strtol(optarg, &endptr, 0); if (*endptr != '\0' || endptr == optarg || hours <= 0) { usage("<hours> must be a positive number"); goto end; } validity += 3600*hours; } continue; case 'S': /* --startdate */ if (optarg == NULL || strlen(optarg) != 15 || optarg[14] != 'Z') { usage("date format must be YYYYMMDDHHMMSSZ"); goto end; } else { chunk_t date = { optarg, 15 }; notBefore = asn1_to_time(&date, ASN1_GENERALIZEDTIME); } continue; case 'E': /* --enddate */ if (optarg == NULL || strlen(optarg) != 15 || optarg[14] != 'Z') { usage("date format must be YYYYMMDDHHMMSSZ"); goto end; } else { chunk_t date = { optarg, 15 }; notAfter = asn1_to_time(&date, ASN1_GENERALIZEDTIME); } continue; case 'o': /* --out */ outfile = optarg; continue; case 'd': /* --debug */ debug_level = atoi(optarg); continue; default: usage(""); status = 0; goto end; } /* break from loop */ break; } if (optind != argc) { usage("unexpected argument"); goto end; } DBG1(DBG_LIB, "starting openac (strongSwan Version %s)", VERSION); /* load the signer's RSA private key */ if (keyfile != NULL) { mem_cred_t *mem; shared_key_t *shared; mem = mem_cred_create(); lib->credmgr->add_set(lib->credmgr, &mem->set); shared = shared_key_create(SHARED_PRIVATE_KEY_PASS, chunk_clone(passphrase)); mem->add_shared(mem, shared, NULL); signerKey = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, KEY_RSA, BUILD_FROM_FILE, keyfile, BUILD_END); lib->credmgr->remove_set(lib->credmgr, &mem->set); mem->destroy(mem); if (signerKey == NULL) { goto end; } DBG1(DBG_LIB, " loaded private key file '%s'", keyfile); } /* load the signer's X.509 certificate */ if (certfile != NULL) { signerCert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, BUILD_FROM_FILE, certfile, BUILD_END); if (signerCert == NULL) { goto end; } } /* load the users's X.509 certificate */ if (usercertfile != NULL) { userCert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, BUILD_FROM_FILE, usercertfile, BUILD_END); if (userCert == NULL) { goto end; } } /* compute validity interval */ validity = (validity)? validity : DEFAULT_VALIDITY; notBefore = (notBefore == UNDEFINED_TIME) ? time(NULL) : notBefore; notAfter = (notAfter == UNDEFINED_TIME) ? time(NULL) + validity : notAfter; /* build and parse attribute certificate */ if (userCert != NULL && signerCert != NULL && signerKey != NULL && outfile != NULL) { /* read the serial number and increment it by one */ serial = read_serial(); attr_cert = lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509_AC, BUILD_CERT, userCert, BUILD_NOT_BEFORE_TIME, notBefore, BUILD_NOT_AFTER_TIME, notAfter, BUILD_SERIAL, serial, BUILD_IETF_GROUP_ATTR, groups, BUILD_SIGNING_CERT, signerCert, BUILD_SIGNING_KEY, signerKey, BUILD_END); if (!attr_cert) { goto end; } /* write the attribute certificate to file */ if (attr_cert->get_encoding(attr_cert, CERT_ASN1_DER, &attr_chunk)) { if (chunk_write(attr_chunk, outfile, 0022, TRUE)) { DBG1(DBG_APP, " written attribute cert file '%s' (%d bytes)", outfile, attr_chunk.len); write_serial(serial); status = 0; } else { DBG1(DBG_APP, " writing attribute cert file '%s' failed: %s", outfile, strerror(errno)); } } } else { usage("some of the mandatory parameters --usercert --cert --key --out " "are missing"); } end: /* delete all dynamically allocated objects */ DESTROY_IF(signerKey); DESTROY_IF(signerCert); DESTROY_IF(userCert); DESTROY_IF(attr_cert); free(attr_chunk.ptr); free(serial.ptr); closelog(); dbg = dbg_default; options->destroy(options); exit(status); }
// Return a link, an image, or a literal close bracket. static cmark_node* handle_close_bracket(subject* subj, cmark_node *parent) { bufsize_t initial_pos; bufsize_t starturl, endurl, starttitle, endtitle, endall; bufsize_t n; bufsize_t sps; cmark_reference *ref; bool is_image = false; cmark_chunk url_chunk, title_chunk; cmark_chunk url, title; delimiter *opener; cmark_node *link_text; cmark_node *inl; cmark_chunk raw_label; int found_label; advance(subj); // advance past ] initial_pos = subj->pos; // look through list of delimiters for a [ or ! opener = subj->last_delim; while (opener) { if (opener->delim_char == '[' || opener->delim_char == '!') { break; } opener = opener->previous; } if (opener == NULL) { return make_str(cmark_chunk_literal("]")); } if (!opener->active) { // take delimiter off stack remove_delimiter(subj, opener); return make_str(cmark_chunk_literal("]")); } // If we got here, we matched a potential link/image text. is_image = opener->delim_char == '!'; link_text = opener->inl_text->next; // Now we check to see if it's a link/image. // First, look for an inline link. if (peek_char(subj) == '(' && ((sps = scan_spacechars(&subj->input, subj->pos + 1)) > -1) && ((n = scan_link_url(&subj->input, subj->pos + 1 + sps)) > -1)) { // try to parse an explicit link: starturl = subj->pos + 1 + sps; // after ( endurl = starturl + n; starttitle = endurl + scan_spacechars(&subj->input, endurl); // ensure there are spaces btw url and title endtitle = (starttitle == endurl) ? starttitle : starttitle + scan_link_title(&subj->input, starttitle); endall = endtitle + scan_spacechars(&subj->input, endtitle); if (peek_at(subj, endall) == ')') { subj->pos = endall + 1; url_chunk = cmark_chunk_dup(&subj->input, starturl, endurl - starturl); title_chunk = cmark_chunk_dup(&subj->input, starttitle, endtitle - starttitle); url = cmark_clean_url(&url_chunk); title = cmark_clean_title(&title_chunk); cmark_chunk_free(&url_chunk); cmark_chunk_free(&title_chunk); goto match; } else { goto noMatch; } } // Next, look for a following [link label] that matches in refmap. // skip spaces subj->pos = subj->pos + scan_spacechars(&subj->input, subj->pos); raw_label = cmark_chunk_literal(""); found_label = link_label(subj, &raw_label); if (!found_label || raw_label.len == 0) { cmark_chunk_free(&raw_label); raw_label = cmark_chunk_dup(&subj->input, opener->position, initial_pos - opener->position - 1); } if (!found_label) { // If we have a shortcut reference link, back up // to before the spacse we skipped. subj->pos = initial_pos; } ref = cmark_reference_lookup(subj->refmap, &raw_label); cmark_chunk_free(&raw_label); if (ref != NULL) { // found url = chunk_clone(&ref->url); title = chunk_clone(&ref->title); goto match; } else { goto noMatch; } noMatch: // If we fall through to here, it means we didn't match a link: remove_delimiter(subj, opener); // remove this opener from delimiter list subj->pos = initial_pos; return make_str(cmark_chunk_literal("]")); match: inl = opener->inl_text; inl->type = is_image ? CMARK_NODE_IMAGE : CMARK_NODE_LINK; cmark_chunk_free(&inl->as.literal); inl->first_child = link_text; process_emphasis(subj, opener); inl->as.link.url = url; inl->as.link.title = title; inl->next = NULL; if (link_text) { cmark_node *tmp; link_text->prev = NULL; for (tmp = link_text; tmp->next != NULL; tmp = tmp->next) { tmp->parent = inl; } tmp->parent = inl; inl->last_child = tmp; } parent->last_child = inl; // Now, if we have a link, we also want to deactivate earlier link // delimiters. (This code can be removed if we decide to allow links // inside links.) remove_delimiter(subj, opener); if (!is_image) { opener = subj->last_delim; while (opener != NULL) { if (opener->delim_char == '[') { if (!opener->active) { break; } else { opener->active = false; } } opener = opener->previous; } } return NULL; }