static void _natd_hash(const struct hash_desc *hasher, unsigned char *hash , u_int8_t *icookie, u_int8_t *rcookie , const ip_address *ip, u_int16_t port) { union hash_ctx ctx; if (is_zero_cookie(icookie)) DBG_log("_natd_hash: Warning, icookie is zero !!"); if (is_zero_cookie(rcookie)) DBG_log("_natd_hash: Warning, rcookie is zero !!"); /** * draft-ietf-ipsec-nat-t-ike-01.txt * * HASH = HASH(CKY-I | CKY-R | IP | Port) * * All values in network order */ hasher->hash_init(&ctx); hasher->hash_update(&ctx, icookie, COOKIE_SIZE); hasher->hash_update(&ctx, rcookie, COOKIE_SIZE); switch (addrtypeof(ip)) { case AF_INET: hasher->hash_update(&ctx, (const u_char *)&ip->u.v4.sin_addr.s_addr, sizeof(ip->u.v4.sin_addr.s_addr)); break; case AF_INET6: hasher->hash_update(&ctx, (const u_char *)&ip->u.v6.sin6_addr.s6_addr, sizeof(ip->u.v6.sin6_addr.s6_addr)); break; } hasher->hash_update(&ctx, (const u_char *)&port, sizeof(u_int16_t)); hasher->hash_final(hash, &ctx); #ifdef NAT_D_DEBUG DBG(DBG_NATT, DBG_log("_natd_hash: hasher=%p(%d)", hasher, (int)hasher->hash_digest_len); DBG_dump("_natd_hash: icookie=", icookie, COOKIE_SIZE); DBG_dump("_natd_hash: rcookie=", rcookie, COOKIE_SIZE); switch (addrtypeof(ip)) { case AF_INET: DBG_dump("_natd_hash: ip=", &ip->u.v4.sin_addr.s_addr, sizeof(ip->u.v4.sin_addr.s_addr)); break; } DBG_log("_natd_hash: port=%d", ntohs(port)); DBG_dump("_natd_hash: hash=", hash, hasher->hash_digest_len); );
static void db_prop_print(struct db_prop *p) { struct db_trans *t; struct db_attr *a; int ti, ai; enum_names *n, *n_at, *n_av; DBG_log("protoid=\"%s\"\n", enum_name(&protocol_names, p->protoid)); for (ti=0, t=p->trans; ti< p->trans_cnt; ti++, t++) { switch( p->protoid) { case PROTO_ISAKMP: n=&isakmp_transformid_names; break; case PROTO_IPSEC_ESP: n=&esp_transformid_names; break; case PROTO_IPSEC_AH: n=&ah_transformid_names; break; default: continue; } DBG_log(" transid=\"%s\"\n", enum_name(n, t->transid)); for (ai=0, a=t->attrs; ai < t->attr_cnt; ai++, a++) { int i; switch( p->protoid) { case PROTO_ISAKMP: n_at=&oakley_attr_names; i=a->type|ISAKMP_ATTR_AF_TV; n_av=oakley_attr_val_descs[(i)&ISAKMP_ATTR_RTYPE_MASK]; break; case PROTO_IPSEC_AH: case PROTO_IPSEC_ESP: n_at=&ipsec_attr_names; i=a->type|ISAKMP_ATTR_AF_TV; n_av=ipsec_attr_val_descs[(i)&ISAKMP_ATTR_RTYPE_MASK]; break; default: continue; } DBG_log(" type=\"%s\" value=\"%s\"\n", enum_name(n_at, i), enum_name(n_av, a->val)); } } }
/* * Create proposal with runtime kernel algos, merging * with passed proposal if not NULL * * for now this function does free() previous returned * malloced pointer (this quirk allows easier spdb.c change) */ struct db_context * kernel_alg_db_new(struct alg_info_esp *alg_info, lset_t policy, bool logit) { int ealg_i, aalg_i, tn=0; int i; const struct esp_info *esp_info; struct esp_info tmp_esp_info; struct db_context *ctx_new=NULL; struct db_trans *t; struct db_prop *prop; int trans_cnt; bool success = TRUE; if (!(policy & POLICY_ENCRYPT)) { /* possible for AH-only modes */ DBG(DBG_CONTROL , DBG_log("algo code only works for encryption modes")); return NULL; } trans_cnt=(esp_ealg_num*esp_aalg_num); DBG(DBG_EMITTING, DBG_log("kernel_alg_db_new() " "initial trans_cnt=%d", trans_cnt)); /* pass aprox. number of transforms and attributes */ ctx_new = db_prop_new(PROTO_IPSEC_ESP, trans_cnt, trans_cnt * 2); /* * Loop: for each element (struct esp_info) of * alg_info, if kernel support is present then * build the transform (and attrs) * * if NULL alg_info, propose everything ... */ /* passert(alg_info!=0); */ if (alg_info) { ALG_INFO_ESP_FOREACH(alg_info, esp_info, i) { bool thistime; tmp_esp_info = *esp_info; thistime = kernel_alg_db_add(ctx_new , &tmp_esp_info , policy, logit); if(thistime == FALSE) { success=FALSE; } } } else {
/* used by kernel_netlink.c and kernel_bsdkame.c */ int kernel_alg_add(int satype, int exttype, const struct sadb_alg *sadb_alg) { struct sadb_alg *alg_p, tmp_alg; uint8_t alg_id = sadb_alg->sadb_alg_id; if (DBGP(DBG_KERNEL|DBG_CRYPT)) { const char *exttype_name = exttype == SADB_EXT_SUPPORTED_AUTH ? "SADB_EXT_SUPPORTED_AUTH" : exttype == SADB_EXT_SUPPORTED_ENCRYPT ? "SADB_EXT_SUPPORTED_ENCRYPT" : "SADB_EXT_SUPPORTED_???"; struct esb_buf alg_name_buf; /* * XXX: The ALG_ID value found here comes from the * Linux kernel (see libreswan/pfkeyv2.h) so using * AH_TRANSFORMID_NAMES and ESP_TRANSFORMID_NAMES is * only an approximation. */ const char *alg_name = exttype == SADB_EXT_SUPPORTED_AUTH ? enum_showb(&ah_transformid_names, alg_id, &alg_name_buf) : exttype == SADB_EXT_SUPPORTED_ENCRYPT ? enum_showb(&esp_transformid_names, alg_id, &alg_name_buf) : "???"; const char *satype_name = satype == SADB_SATYPE_ESP ? "SADB_SATYPE_ESP" : satype == SADB_SATYPE_AH ? "SADB_SATYPE_AH" : "SADB_SATYPE_???"; DBG_log("kernel_alg_add(): satype=%d(%s), exttype=%d(%s), alg_id=%d(%s), alg_ivlen=%d, alg_minbits=%d, alg_maxbits=%d", satype, satype_name, exttype, exttype_name, alg_id, alg_name, sadb_alg->sadb_alg_ivlen, sadb_alg->sadb_alg_minbits, sadb_alg->sadb_alg_maxbits); } alg_p = sadb_alg_ptr(satype, exttype, alg_id, TRUE); if (alg_p == NULL) { DBG(DBG_KERNEL, DBG_log("kernel_alg_add(%d,%d,%d) fails because alg combo is invalid", satype, exttype, alg_id)); return -1; } /* This logic "mimics" KLIPS: first algo implementation will be used */ if (alg_p->sadb_alg_id != 0) { DBG(DBG_KERNEL, DBG_log("kernel_alg_add(): discarding already setup satype=%d, exttype=%d, alg_id=%d", satype, exttype, alg_id); );
static void load_setup(starter_config_t *cfg, config_parsed_t *cfgp) { kw_list_t *kw; DBG(DBG_CONTROL, DBG_log("Loading config setup") ) for (kw = cfgp->config_setup; kw; kw = kw->next) { bool assigned = FALSE; kw_token_t token = kw->entry->token; if (token < KW_SETUP_FIRST || token > KW_SETUP_LAST) { plog("# unsupported keyword '%s' in config setup", kw->entry->name); cfg->err++; continue; } if (!assign_arg(token, KW_SETUP_FIRST, kw, (char *)cfg, &assigned)) { plog(" bad argument value in config setup"); cfg->err++; continue; } } }
/* * Processing FOR KE values. */ void unpack_KE(struct state *st , struct pluto_crypto_req *r , chunk_t *g) { struct pcr_kenonce *kn = &r->pcr_d.kn; if (!st->st_sec_in_use) { st->st_sec_in_use = TRUE; freeanychunk(*g); /* happens in odd error cases */ clonetochunk(*g, wire_chunk_ptr(kn, &(kn->gi)) , kn->gi.len, "saved gi value"); #ifdef HAVE_LIBNSS DBG(DBG_CRYPT, DBG_log("saving DH priv (local secret) and pub key into state struc")); clonetochunk(st->st_sec_chunk , wire_chunk_ptr(kn, &(kn->secret)) , kn->secret.len, "pointer to DH private key (secret)"); clonetochunk(st->pubk , wire_chunk_ptr(kn, &(kn->pubk)) , kn->pubk.len, "pointer to DH public key"); #else n_to_mpz(&st->st_sec , wire_chunk_ptr(kn, &(kn->secret)) , kn->secret.len); clonetochunk(st->st_sec_chunk , wire_chunk_ptr(kn, &(kn->secret)) , kn->secret.len, "long term secret"); #endif } }
/** * Lock access to the chained authcert list */ void lock_authcert_list(const char *who) { pthread_mutex_lock(&authcert_list_mutex); DBG(DBG_CONTROLMORE, DBG_log("authcert list locked by '%s'", who) ) }
/** * Unlock access to the chained ocsp fetch request list */ static void unlock_ocsp_fetch_list(const char *who) { DBG(DBG_CONTROLMORE, DBG_log("ocsp fetch request list unlocked by '%s'", who) ) pthread_mutex_unlock(&ocsp_fetch_list_mutex); }
/** * Unlock access to the ca info list */ extern void unlock_ca_info_list(const char *who) { DBG(DBG_CONTROLMORE, DBG_log("ca info list unlocked by '%s'", who) ) pthread_mutex_unlock(&ca_info_list_mutex); }
/** * Unlock access to the chained crl list */ void unlock_crl_list(const char *who) { DBG(DBG_CONTROLMORE, DBG_log("crl list unlocked by '%s'", who) ) pthread_mutex_unlock(&crl_list_mutex); }
/* * add an authority certificate to the chained list */ void add_authcert(x509cert_t *cert, u_char auth_flags) { x509cert_t *old_cert; /* set authority flags */ cert->authority_flags |= auth_flags; lock_authcert_list("add_authcert"); old_cert = get_authcert(cert->subject, cert->serialNumber, cert->subjectKeyID, auth_flags); if (old_cert != NULL) { if (same_x509cert(cert, old_cert)) { /* * cert is already present, just add additional * authority flags */ old_cert->authority_flags |= cert->authority_flags; DBG(DBG_X509 | DBG_PARSING, DBG_log(" authcert is already present and identical"); ); unlock_authcert_list("add_authcert"); free_x509cert(cert); return; } else {
/** * Parse X.501 attributes */ bool parse_attributes(chunk_t blob, scep_attributes_t *attrs) { asn1_parser_t *parser; chunk_t object; int oid = OID_UNKNOWN; int objectID; bool success = FALSE; parser = asn1_parser_create(attributesObjects, blob); DBG(DBG_CONTROL | DBG_PARSING, DBG_log("parsing attributes") ) while (parser->iterate(parser, &objectID, &object)) { switch (objectID) { case ATTRIBUTE_OBJ_TYPE: oid = asn1_known_oid(object); break; case ATTRIBUTE_OBJ_VALUE: if (!extract_attribute(oid, object, parser->get_level(parser), attrs)) { goto end; } } } success = parser->success(parser); end: parser->destroy(parser); return success; }
static int _iface_down(int sock, struct st_ipsec_if *iface) { struct ifreq req; int ret = 0; iface->up = 0; strncpy(req.ifr_name, iface->name, IFNAMSIZ); if (ioctl(sock, SIOCGIFFLAGS, &req)!=0) return ret; if (req.ifr_flags & IFF_UP) { DBG(DBG_CONTROL, DBG_log("shutting down interface %s/%s", iface->name, iface->phys) ) req.ifr_flags &= ~IFF_UP; ioctl(sock, SIOCSIFFLAGS, &req); ret = 1; } /* unset addr */ memset(&req.ifr_addr, 0, sizeof(req.ifr_addr)); req.ifr_addr.sa_family = AF_INET; ioctl(sock, SIOCSIFADDR, &req); /* tncfg --detach */ ioctl(sock, IPSEC_DEL_DEV, &req); memset(iface->phys, 0, sizeof(iface->phys)); return ret; }
void init_nat_traversal(unsigned int keep_alive_period) { { FILE *f = fopen("/proc/net/ipsec/natt", "r"); /* ??? this only checks if the file starts with '0'; seems sloppy */ if (f != NULL) { int n = getc(f); if (n == '0') { nat_traversal_enabled = FALSE; libreswan_log( " KLIPS does not have NAT-Traversal built in (see /proc/net/ipsec/natt)\n"); } fclose(f); } } if (keep_alive_period != 0) nat_kap = keep_alive_period; DBG(DBG_NATT, DBG_log("init_nat_traversal() initialized with keep_alive=%d", keep_alive_period)); libreswan_log("NAT-Traversal support %s", nat_traversal_enabled ? " [enabled]" : " [disabled]"); }
/* * parse X.501 attributes */ bool parse_attributes(chunk_t blob, scep_attributes_t *attrs) { asn1_ctx_t ctx; chunk_t object; u_int level; int oid = OID_UNKNOWN; int objectID = 0; asn1_init(&ctx, blob, 0, FALSE, DBG_RAW); DBG(DBG_CONTROL | DBG_PARSING, DBG_log("parsing attributes") ) while (objectID < ATTRIBUTE_OBJ_ROOF) { if (!extract_object(attributesObjects, &objectID , &object, &level, &ctx)) return FALSE; switch (objectID) { case ATTRIBUTE_OBJ_TYPE: oid = known_oid(object); break; case ATTRIBUTE_OBJ_VALUE: if (!extract_attribute(oid, object, level, attrs)) return FALSE; } objectID++; } return TRUE; }
/* * find a boundary of the form -----tag name----- */ static bool find_boundary(const char* tag, chunk_t *line) { chunk_t name = empty_chunk; if (!present("-----", line)) return FALSE; if (!present(tag, line)) return FALSE; if (*line->ptr != ' ') return FALSE; line->ptr++; line->len--; /* extract name */ name.ptr = line->ptr; while (line->len > 0) { if (present("-----", line)) { DBG(DBG_PARSING, DBG_log(" -----%s %.*s-----", tag, (int)name.len, name.ptr); ) return TRUE; }
/* process an input packet, possibly generating a reply. * * If all goes well, this routine eventually calls a state-specific * transition function. */ void process_packet(struct msg_digest **mdp) { struct msg_digest *md = *mdp; int vmaj, vmin; if (!in_struct(&md->hdr, &isakmp_hdr_desc, &md->packet_pbs, &md->message_pbs)) { /* The packet was very badly mangled. We can't be sure of any * content - not even to look for major version number! * So we'll just drop it. */ libreswan_log("Received packet with mangled IKE header - dropped"); send_notification_from_md(md, PAYLOAD_MALFORMED); return; } if (md->packet_pbs.roof > md->message_pbs.roof) { /* Some (old?) versions of the Cisco VPN client send an additional * 16 bytes of zero bytes - Complain but accept it */ DBG(DBG_CONTROL, { DBG_log( "size (%u) in received packet is larger than the size " "specified in ISAKMP HDR (%u) - ignoring extraneous bytes", (unsigned) pbs_room(&md->packet_pbs), md->hdr.isa_length); DBG_dump("extraneous bytes:", md->message_pbs.roof, md->packet_pbs.roof - md->message_pbs.roof); });
CK_MECHANISM_TYPE nss_key_derivation_mech(const struct hash_desc *hasher) { CK_MECHANISM_TYPE mechanism = 0x80000000; switch (hasher->common.algo_id) { case OAKLEY_MD5: mechanism = CKM_MD5_KEY_DERIVATION; break; case OAKLEY_SHA1: mechanism = CKM_SHA1_KEY_DERIVATION; break; case OAKLEY_SHA2_256: mechanism = CKM_SHA256_KEY_DERIVATION; break; case OAKLEY_SHA2_384: mechanism = CKM_SHA384_KEY_DERIVATION; break; case OAKLEY_SHA2_512: mechanism = CKM_SHA512_KEY_DERIVATION; break; default: DBG(DBG_CRYPT, DBG_log("NSS: key derivation mechanism not supported")); break; } return mechanism; }
/** * Unlock access to the ocsp cache */ extern void unlock_ocsp_cache(const char *who) { DBG(DBG_CONTROLMORE, DBG_log("ocsp cache unlocked by '%s'", who) ) pthread_mutex_unlock(&ocsp_cache_mutex); }
void extra_debugging(const struct connection *c) { if (c == NULL) { reset_debugging(); return; } if (c != NULL && c->extra_debugging != 0) { libreswan_log("extra debugging enabled for connection: %s", bitnamesof(debug_bit_names, c->extra_debugging & ~cur_debugging)); set_debugging(cur_debugging | c->extra_debugging); } /* * if any debugging is no, make sure that we log the connection * we are processing, because it may not be clear in later debugging. */ if (cur_debugging) { char b1[CONN_INST_BUF]; fmt_conn_instance(c, b1); DBG_log("processing connection %s%s", c->name, b1); } }
/** * Lock access to the chained crl fetch request list */ static void lock_crl_fetch_list(const char *who) { pthread_mutex_lock(&crl_fetch_list_mutex); DBG(DBG_CONTROLMORE, DBG_log("crl fetch request list locked by '%s'", who) ) }
/* * Raw add routine: only checks for no duplicates */ static void __alg_info_esp_add (struct alg_info_esp *alg_info , int ealg_id, unsigned ek_bits , int aalg_id, unsigned ak_bits) { struct esp_info *esp_info=alg_info->esp; unsigned cnt=alg_info->alg_info_cnt, i; /* check for overflows */ passert(cnt < elemsof(alg_info->esp)); /* dont add duplicates */ for (i=0;i<cnt;i++) if ( esp_info[i].esp_ealg_id==ealg_id && (!ek_bits || esp_info[i].esp_ealg_keylen==ek_bits) && esp_info[i].esp_aalg_id==aalg_id && (!ak_bits || esp_info[i].esp_aalg_keylen==ak_bits)) return; esp_info[cnt].esp_ealg_id=ealg_id; esp_info[cnt].esp_ealg_keylen=ek_bits; esp_info[cnt].esp_aalg_id=aalg_id; esp_info[cnt].esp_aalg_keylen=ak_bits; /* sadb values */ esp_info[cnt].encryptalg=ealg_id; esp_info[cnt].authalg=alg_info_esp_aa2sadb(aalg_id); alg_info->alg_info_cnt++; DBG(DBG_CRYPT, DBG_log("__alg_info_esp_add() " "ealg=%d aalg=%d cnt=%d", ealg_id, aalg_id, alg_info->alg_info_cnt)); }
/** * Unlock access to my certs and keys */ void unlock_certs_and_keys(const char *who) { DBG(DBG_CONTROLMORE, DBG_log("certs and keys unlocked by '%s'", who) ) pthread_mutex_unlock(&certs_and_keys_mutex); }
/* * Search enum_name array with in prefixed and postfixed uppercase */ int alg_enum_search_ppfix (enum_names *ed, const char *prefix , const char *postfix, const char *str , int str_len) { char buf[64]; char *ptr; int ret; int len=sizeof(buf)-1; /* reserve space for final \0 */ for (ptr=buf; *prefix; *ptr++=*prefix++, len--); while (str_len--&&len--&&*str) { *ptr++=toupper(*str++); } while (len--&&*postfix) { *ptr++=*postfix++; } *ptr=0; DBG(DBG_CRYPT, DBG_log("enum_search_ppfixi () " "calling enum_search(%p, \"%s\")", ed, buf)); ret=enum_search(ed, buf); return ret; }
void sha512_write(sha512_context *ctx, const unsigned char *datap, int length) { SECStatus status = PK11_DigestOp(ctx->ctx_nss, datap, length); PR_ASSERT(status == SECSuccess); DBG(DBG_CRYPT, DBG_log("NSS: sha512 write end")); }
/* Insert a state object in the hash table. The object is inserted * at the begining of list. * Needs cookies, connection, and msgid. */ void insert_state(struct state *st) { unsigned int bucket; struct state **p = state_hash(st->st_icookie, st->st_rcookie, &bucket); passert(st->st_hashchain_prev == NULL && st->st_hashchain_next == NULL); DBG(DBG_CONTROL , DBG_log("inserting state object #%lu bucket: %u" , st->st_serialno, bucket)); if (*p != NULL) { passert((*p)->st_hashchain_prev == NULL); (*p)->st_hashchain_prev = st; } st->st_hashchain_next = *p; *p = st; /* Ensure that somebody is in charge of killing this state: * if no event is scheduled for it, schedule one to discard the state. * If nothing goes wrong, this event will be replaced by * a more appropriate one. */ if (st->st_event == NULL) event_schedule(EVENT_SO_DISCARD, 0, st); refresh_state(st); }
/* * we write out an empty record with the right WHACK magic. * this should permit a later mechanism to figure out the * endianess of the file, since we will get records from * other systems for analysis eventually. */ static bool openwhackrecordfile(char *file) { char when[256]; char FQDN[HOST_NAME_MAX + 1]; u_int32_t magic; struct tm tm1, *tm; realtime_t n = realnow(); strcpy(FQDN, "unknown host"); gethostname(FQDN, sizeof(FQDN)); strncpy(whackrecordname, file, sizeof(whackrecordname)-1); whackrecordname[sizeof(whackrecordname)-1] = '\0'; /* ensure NUL termination */ whackrecordfile = fopen(whackrecordname, "w"); if (whackrecordfile == NULL) { libreswan_log("Failed to open whack record file: '%s'", whackrecordname); return FALSE; } tm = localtime_r(&n.real_secs, &tm1); strftime(when, sizeof(when), "%F %T", tm); fprintf(whackrecordfile, "#!-pluto-whack-file- recorded on %s on %s", FQDN, when); magic = WHACK_BASIC_MAGIC; writewhackrecord((char *)&magic, sizeof(magic)); DBG(DBG_CONTROL, DBG_log("started recording whack messages to %s", whackrecordname)); return TRUE; }
/* * unlink a state object from the hash table that had a zero * rcookie before, and rehash it into the right place */ void rehash_state(struct state *st) { unsigned bucket = 0; /* unlink from forward chain */ struct state **p = st->st_hashchain_prev == NULL ? state_hash(st->st_icookie, zero_cookie, &bucket) : &st->st_hashchain_prev->st_hashchain_next; DBG(DBG_CONTROL , DBG_log("rehashing state object #%lu from bucket %u" , st->st_serialno, bucket)); /* unlink from forward chain */ passert(*p == st); *p = st->st_hashchain_next; /* unlink from backward chain */ if (st->st_hashchain_next != NULL) { passert(st->st_hashchain_next->st_hashchain_prev == st); st->st_hashchain_next->st_hashchain_prev = st->st_hashchain_prev; } st->st_hashchain_next = st->st_hashchain_prev = NULL; /* now, re-insert */ insert_state(st); }
/* load a coded key or certificate file with autodetection * of binary DER or base64 PEM ASN.1 formats and armored PGP format */ bool load_coded_file(const char *filename, prompt_pass_t *pass, int verbose, const char *type, chunk_t *blob, bool *pgp) { err_t ugh = NULL; FILE *fd; fd = fopen(filename, "r"); if (fd) { int bytes; fseek(fd, 0, SEEK_END ); blob->len = ftell(fd); rewind(fd); blob->ptr = alloc_bytes(blob->len, type); bytes = fread(blob->ptr, 1, blob->len, fd); fclose(fd); if(verbose) { openswan_log(" loaded %s file '%s' (%d bytes)", type, filename, bytes); } *pgp = FALSE; /* try DER format */ if (is_asn1(*blob)) { DBG(DBG_PARSING, DBG_log(" file coded in DER format"); ) return TRUE; }
/* * we write out an empty record with the right WHACK magic. * this should permit a later mechanism to figure out the * endianess of the file, since we will get records from * other systems for analysis eventually. */ static bool openwhackrecordfile(char *file) { char when[256]; char FQDN[HOST_NAME_MAX + 1]; u_int32_t magic; struct tm tm1, *tm; time_t n; strcpy(FQDN, "unknown host"); gethostname(FQDN, sizeof(FQDN)); strncpy(whackrecordname, file, sizeof(whackrecordname)); whackrecordfile = fopen(whackrecordname, "w"); if(whackrecordfile==NULL) { openswan_log("Failed to open whack record file: '%s'\n" , whackrecordname); return FALSE; } time(&n); tm = localtime_r(&n, &tm1); strftime(when, sizeof(when), "%F %T", tm); fprintf(whackrecordfile, "#!-pluto-whack-file- recorded on %s on %s\n", FQDN, when); magic = WHACK_BASIC_MAGIC; writewhackrecord((char *)&magic, 4); DBG(DBG_CONTROL , DBG_log("started recording whack messages to %s\n" , whackrecordname)); return TRUE; }