Esempio n. 1
0
int shfs_ref_get(shfs_ino_t *file,
                 shfs_t **ref_fs_p, shfs_ino_t **ref_p)
{
    shfs_ino_t *ref;
    shfs_ino_t *parent;
    shpeer_t *peer;
    shfs_t *fs;
    shkey_t *hier;
    shbuf_t *buff;
    char path[SHFS_PATH_MAX];
    int hier_cnt;
    int err;
    int i;

    *ref_p = NULL;
    *ref_fs_p = NULL;

    if (!file || !file->tree)
        return (SHERR_INVAL);

    buff = shbuf_init();
    err = _shfs_ref_raw_read(file, buff);
    if (err)
        return (err);

    peer = (shpeer_t *)shbuf_data(buff);
    hier = (shkey_t *)(shbuf_data(buff) + sizeof(shpeer_t));

    fs = shfs_init(peer);
    if (!fs)
        return (SHERR_IO);

    memset(path, 0, sizeof(path));
    strcpy(path, "/");
    ref = fs->fsbase_ino;
    for (i = SHFS_MAX_REFERENCE_HIERARCHY - 1; i >= 0; i--) {
        if (shkey_cmp(&hier[i], ashkey_blank()))
            continue;
        if (shkey_cmp(&hier[i], shfs_token(file->tree->fsbase_ino)))
            continue;

        ref = shfs_inode_load(ref, &hier[i]);
        if (!ref) {
            shfs_free(&fs);
            return (SHERR_NOENT);
        }

        if (shfs_type(ref) == SHINODE_DIRECTORY)
            strncat(path, "/", SHFS_PATH_MAX - strlen(path) - 1);
        strncat(path, shfs_filename(ref), SHFS_PATH_MAX - strlen(path) - 1);
    }

    shbuf_free(&buff);

    *ref_p = ref;
    *ref_fs_p = fs;

    return (0);
}
Esempio n. 2
0
/** reference a revision by name */
int shfs_rev_ref(shfs_ino_t *file, char *group, char *name, shfs_ino_t *rev)
{
  shfs_ino_t *branch;
  shfs_ino_t *ref;
  shkey_t *ref_key;
  char buf[SHFS_PATH_MAX];
  int err;

  if (!rev) {
    return (SHERR_INVAL);
  }

  if (shfs_type(rev) != SHINODE_REVISION)
    return (SHERR_INVAL);

  ref_key = shkey_hexgen(shfs_filename(rev));
  if (!ref_key)
    return (SHERR_IO);

  if (shkey_cmp(ref_key, ashkey_blank())) {
    /* not a revision (filename has no hex key) */
    shkey_free(&ref_key);
    return (SHERR_INVAL);
  }

  memset(buf, 0, sizeof(buf));
  snprintf(buf, sizeof(buf)-1, "%s/%s", group, name);
  err = shfs_obj_set(file, buf, ref_key);
  shkey_free(&ref_key);
  if (err)
    return (err);

  return (0);
}
Esempio n. 3
0
/**
 * @see shsig_shr_verify()
 */
static int _shcert_sign_verify_shr(shcert_t *cert, shcert_t *parent)
{
  shkey_t *key;
  unsigned char *enc_data;
  size_t enc_len;
  int err;

  if (!parent)
    return (SHERR_INVAL);

  err = shencode((char *)&parent->cert_sub.ent_sig.sig_key, sizeof(shkey_t),
    &enc_data, &enc_len, &parent->cert_iss.ent_sig.sig_key);
  if (err)
    return (err);

  key = shkey_bin(enc_data, enc_len);
  free(enc_data);
  if (!shkey_cmp(key, &cert->cert_sub.ent_sig.sig_key)) {
    /* encrypted key is not validated. */
    shkey_free(&key);
    return (SHERR_KEYREJECTED);
  }

  shkey_free(&key);
  return (0); 
}
Esempio n. 4
0
int shpam_shadow_setpass(shfs_ino_t *file, shseed_t *seed, shkey_t *sess_key)
{
  shadow_t *ent;
  shadow_t save;
  shkey_t *seed_key;
  int err;

  seed_key = shkey_bin((char *)&seed->seed_uid, sizeof(seed->seed_uid));
  ent = shpam_shadow(file, seed_key);
  shkey_free(&seed_key);
  if (!ent)
    return (SHERR_NOENT);

  memcpy(&save, ent, sizeof(shadow_t));
  if (shtime64() >= save.sh_expire)
    return (SHERR_KEYEXPIRED);
  if (!shkey_cmp(&save.sh_sess, sess_key))
    return (SHERR_KEYREJECTED);

  seed_key = shkey_bin((char *)&seed->seed_uid, sizeof(seed->seed_uid));
  err = shpam_shadow_session_expire(file, seed_key, sess_key);
  shkey_free(&seed_key);
  if (err)
    return (err);

  err = shpam_shadow_pass_append(file, seed);
  if (err)
    return (err);

  return (0);
}
Esempio n. 5
0
int shpam_shadow_session_set(shfs_ino_t *file, uint64_t uid, shkey_t *id_key, uint64_t sess_stamp, shkey_t *sess_key)
{
  shadow_t shadow;
  shseed_t save;
  int err;

  err = shpam_pshadow_load(file, uid, &save);
  if (err)
    return (err);

  err = shpam_sess_verify(sess_key, &save.seed_key, sess_stamp, id_key);
  if (err)
    return (err);

  err = shpam_shadow_load(file, uid, &shadow);
  if (err)
    return (err);

  if (!shkey_cmp(id_key, &shadow.sh_id))
    return (SHERR_INVAL);

  shadow.sh_expire = sess_stamp;
  memcpy(&shadow.sh_sess, sess_key, sizeof(shadow.sh_sess));
  err = shpam_shadow_store(file, &shadow);
  if (err)
    return (err);

  return (0);
}
Esempio n. 6
0
int shpam_pshadow_set(shfs_ino_t *file, shseed_t *seed, shkey_t *sess_key)
{
  shadow_t save;
  int err;

  err = shpam_shadow_load(file, seed->seed_uid, &save);
  if (err)
    return (err);

  /* validate session key */
  if (shtime_after(shtime(), save.sh_expire))
    return (SHERR_KEYEXPIRED);
  if (!shkey_cmp(&save.sh_sess, sess_key))
    return (SHERR_KEYREJECTED);

  err = shpam_shadow_session_expire(file, seed->seed_uid, sess_key);
  if (err)
    return (err);

  err = shpam_pshadow_store(file, seed);
  if (err)
    return (err);

  return (0);
}
Esempio n. 7
0
static int _shcert_sign_verify_ecdsa(shcert_t *cert, shcert_t *parent)
{
  shkey_t *pub_key;
  char *hex_data;
  unsigned char data[256];
  int data_len;
  int err;

  if (parent) {
    if (!shkey_cmp(shcert_sub_sig(parent), shcert_iss_sig(cert))) {
      return (SHERR_INVAL);
    }
  }

  hex_data = shkey_hex(&cert->cert_iss.ent_sig.sig_key);
  data_len = strlen(hex_data) / 2;
  if (!data_len) {
    return (SHERR_INVAL);
  }

  memset(data, 0, sizeof(data));
  hex2bin(data, hex_data, data_len);

  pub_key = &cert->cert_sub.ent_sig.sig_key;
  err = shecdsa_verify(pub_key, 
    cert->cert_sub.ent_sig.key.ecdsa.sig_r,
    cert->cert_sub.ent_sig.key.ecdsa.sig_s,
    data, data_len);
  if (err)
    return (err);

  return (0);
}
Esempio n. 8
0
int shpam_shadow_remove(shfs_ino_t *file, uint64_t uid, shkey_t *sess_key)
{
  shadow_t *ent;
  shadow_t save;
  shkey_t *key;
  int err;

  if (!sess_key)
    return (SHERR_NOKEY);

  err = shpam_shadow_load(file, uid, &save);
  if (err) {
    return (err);
}

  if (shtime_after(shtime(), save.sh_expire))
    return (SHERR_KEYEXPIRED);

  if (!shkey_cmp(&save.sh_sess, sess_key))
    return (SHERR_KEYREJECTED);

  key = shkey_bin((char *)&uid, sizeof(uid));
  err = shfs_cred_remove(file, key);
  shkey_free(&key);
  if (err) {
    return (err);
}

  return (0);
}
Esempio n. 9
0
int txop_contract_confirm(shpeer_t *peer, tx_contract_t *contract)
{
  shtime_t now;
  shkey_t *key;
  int sig_ok;

  if (0 != strcmp(contract->con_cur, COIN_USDE) &&
      0 != strcmp(contract->con_cur, COIN_GMC) &&
      0 != strcmp(contract->con_cur, COIN_SYS))
    return (SHERR_INVAL);

  now = shtime();
  if (shtime_before(shtime(), contract->con_birth) ||
      shtime_before(shtime(), contract->con_stamp) ||
      shtime_after(contract->con_birth, contract->con_stamp))
    return (SHERR_TIME);

  key = shkey_hexgen(contract->con_key + 8);
  if (!key)
    return (SHERR_NOKEY);
  sig_ok = shkey_cmp(key, &contract->con_sig);
  shkey_free(&key);
  if (!sig_ok)
    return (SHERR_KEYREJECTED);

  return (0);
}
Esempio n. 10
0
/**
 * @returns An allocated parent transaction or NULL.
 */
tx_t *get_tx_parent(tx_t *tx)
{
  tx_t *p_tx;

  if (0 == shkey_cmp(&tx->tx_pkey, ashkey_blank()))
    return (NULL);

  return ((tx_t *)pstore_load(tx->tx_ptype, shkey_hex(&tx->tx_pkey)));
}
Esempio n. 11
0
/** Determine whether the appropriate context is availale. */
int txward_context_confirm(tx_ward_t *ward, tx_context_t *ctx)
{
  int err;

  if (!shkey_cmp(&ward->ward_ref, &ctx->ctx_ref))
    return (SHERR_INVAL);

  err = shkey_verify(&ward->ward_sig, shkey_crc(&ctx->ctx_ref), 
    &ctx->ctx_sig, ward->ward_tx.tx_stamp);
  if (err)
    return (err);

  return (0);
}
Esempio n. 12
0
void info_table_add_key(info_table_t *table, char *col_name, shkey_t *key)
{
  int idx;

  if (!key || shkey_cmp(ashkey_blank(), key))
    return;

  if (!(run_flags & PFLAG_VERBOSE))
    return;

  idx = info_table_column(table, col_name);
  if (idx != -1)
    table->row->col[idx] = strdup(shkey_print(key));
}
Esempio n. 13
0
shfs_ino_t *shfs_rev_get(shfs_ino_t *repo, shkey_t *rev_key)
{
  shfs_ino_t *rev;

  if (shfs_type(repo) == SHINODE_FILE)
    repo = shfs_inode(repo, NULL, SHINODE_REPOSITORY);
  if (shfs_type(repo) != SHINODE_REPOSITORY)
    return (NULL);

  if (shkey_cmp(rev_key, ashkey_blank()))
    return (NULL);

  return (shfs_inode(repo, (char *)shkey_hex(rev_key), SHINODE_REVISION));
}
Esempio n. 14
0
shadow_t *shpam_shadow(shfs_ino_t *file, shkey_t *seed_key)
{
  static shadow_t ret_shadow;
  int err;

  memset(&ret_shadow, 0, sizeof(ret_shadow));
  err = shfs_cred_load(file, seed_key, (unsigned char *)&ret_shadow, sizeof(ret_shadow));
  if (err)
   return (NULL);
  if (!shkey_cmp(seed_key, &ret_shadow.sh_seed))
    return (NULL);

  return (&ret_shadow);
}
Esempio n. 15
0
int shpam_shadow_verify(shfs_ino_t *file, shkey_t *seed_key)
{
  shadow_t shadow;
  int err;

  memset(&shadow, 0, sizeof(shadow));
  err = shfs_cred_load(file, seed_key, (unsigned char *)&shadow, sizeof(shadow));
  if (err)
    return (SHERR_NOKEY);

  if (!shkey_cmp(seed_key, &shadow.sh_seed))
    return (SHERR_ACCESS);

  return (0);
}
Esempio n. 16
0
int txop_trust_init(shpeer_t *cli_peer, tx_trust_t *trust)
{
  shkey_t *sig_key;
  uint64_t crc;
  int err;

  if (!trust)
    return (SHERR_INVAL);

  if (shkey_cmp(&trust->trust_ctx, ashkey_blank()))
    memcpy(&trust->trust_ctx, ashkey_uniq(), sizeof(trust->trust_ctx));
  tx_sign(trust, &trust->trust_sig, &trust->trust_ctx);

  return (0);
}
Esempio n. 17
0
int shkey_verify(shkey_t *sig, uint64_t crc, shkey_t *key, shtime_t stamp)
{
  shkey_t *sha_key;
  char *ptr;
  int valid;

  sha_key = shkey_cert(key, crc, stamp);

  valid = shkey_cmp(sha_key, sig);
  shkey_free(&sha_key);
  if (!valid)
    return (SHERR_INVAL);

  return (0);
}
Esempio n. 18
0
int update_sexe_userdata(sexe_t *S)
{
  SHFL *fl;
  shjson_t *udata;
  shfs_t *fs;
  shbuf_t *buff;
  shkey_t *k;
  char path[PATH_MAX+1];
  char *str;
  int err;

  k = &S->pname;
  if (shkey_cmp(k, ashkey_blank())) {
fprintf(stderr, "DEBUG: update_sexe_userdata: no app key\n");
    return (0); /* blank */
  }
  sprintf(path, "/sys/data/sexe/%s", shkey_hex(k)); 

  lua_getglobal(S, "userdata");
  udata = sexe_table_get(S);
  if (!udata) {
fprintf(stderr, "DEBUG: update_sexe_userdata: no global 'userdata' variable.\n");
    return (SHERR_INVAL);
  }

  str = shjson_print(udata);
  if (!str) {
fprintf(stderr, "DEBUG: update_sexe_userdata: error encoding JSON.\n");
    return (SHERR_INVAL);
}
  shjson_free(&udata);

  buff = shbuf_init();
  shbuf_catstr(buff, str);
  free(str);


  fs = shfs_init(NULL);
  fl = shfs_file_find(fs, path);
  err = shfs_write(fl, buff);
  shbuf_free(&buff);
  shfs_free(&fs);

  return (err);
}
Esempio n. 19
0
/** Associated a particular context with releasing a ward. */
void txward_context_sign(tx_ward_t *ward, tx_context_t *ctx)
{
  shkey_t *sig_key;

  if (!ward || !ctx)
    return;

  if (!shkey_cmp(&ward->ward_ref, &ctx->ctx_ref))
    return (SHERR_INVAL);

  if (ward->ward_tx.tx_stamp == SHTIME_UNDEFINED)
    ward->ward_tx.tx_stamp = shtime();

  sig_key = shkey_cert(&ctx->ctx_sig,
      shkey_crc(&ctx->ctx_ref), ward->ward_tx.tx_stamp);
  memcpy(&ward->ward_sig, sig_key, sizeof(ward->ward_sig));
  shkey_free(&sig_key);

}
Esempio n. 20
0
int shpam_shadow_delete(shfs_ino_t *file, char *acc_name, shkey_t *sess_key)
{
  shadow_t *ent;
  shadow_t save;
  shkey_t *seed_key;
  int ret_err;
  int err;

  if (!sess_key)
    return (SHERR_INVAL);

  seed_key = shpam_seed(acc_name);
  ent = shpam_shadow(file, seed_key);
  shkey_free(&seed_key);
  if (!ent)
    return (SHERR_NOKEY);

  memcpy(&save, ent, sizeof(shadow_t));

  if (shtime64() >= save.sh_expire)
    return (SHERR_KEYEXPIRED);

  if (!shkey_cmp(&save.sh_sess, sess_key))
    return (SHERR_KEYREJECTED);

  if (save.sh_flag & SHPAM_LOCK)
    return (SHERR_ACCESS);

  ret_err = 0;

  err = shfs_cred_remove(file, &save.sh_seed);
  if (err)
    ret_err = err;

  err = shpam_shadow_pass_remove(file, shpam_uid(acc_name));
  if (err)
    ret_err = err;

  return (ret_err);
}
Esempio n. 21
0
int shpam_shadow_session_expire(shfs_ino_t *file, uint64_t uid, shkey_t *sess_key)
{
  shadow_t *ent;
  shadow_t save;
  int err;

  err = shpam_shadow_load(file, uid, &save);
  if (err)
    return (err);

  if (shtime_after(shtime(), save.sh_expire))
    return (SHERR_KEYEXPIRED);
  if (!shkey_cmp(&save.sh_sess, sess_key))
    return (SHERR_KEYREJECTED);

  save.sh_expire = 0;
  err = shpam_shadow_store(file, &save);
  if (err)
    return (err);

  return (0);
}
Esempio n. 22
0
int confirm_tx_key(txop_t *op, tx_t *tx)
{
  shkey_t *c_key = &tx->tx_key;
  shkey_t *key;
  shbuf_t *buff;
  tx_t *k_tx;
  size_t len;
  int confirm;

  if (!op || !tx)
    return (SHERR_INVAL);

  if (op->op_size == 0)
    return (0);

  /* allocate working copy */
  len = MAX(sizeof(tx_t), op->op_keylen ? op->op_keylen : op->op_size);
  buff = shbuf_init();
  shbuf_cat(buff, (char *)tx, len);

  /* blank out tx key */
  k_tx = (tx_t *)shbuf_data(buff);
  memset(&k_tx->tx_key, '\000', sizeof(k_tx->tx_key));

  /* verify generated tx key matches. */
  key = shkey_bin(shbuf_data(buff), shbuf_size(buff));
  confirm = shkey_cmp(c_key, key);
  shkey_free(&key);
  shbuf_free(&buff);

  if (!confirm) {
    return (SHERR_INVAL);
  }

  return (0);
}
Esempio n. 23
0
/**
 * Generates the working-copy for a particular revision.
 */
int shfs_rev_read(shfs_ino_t *i_rev, shbuf_t *buff)
{
  shfs_ino_t *repo;
  shfs_ino_t *file;
  shfs_ino_t *rev;
  shbuf_t *delta_buff;
  shbuf_t *head_buff;
  shbuf_t *out_buff;
  int err;

  if (shfs_type(i_rev) != SHINODE_REVISION) {
    return (SHERR_INVAL);
  }

  repo = shfs_inode_parent(i_rev);
  if (!repo || shfs_type(repo) != SHINODE_REPOSITORY)
    return (SHERR_IO);

  file = shfs_inode_parent(repo);
  if (!file || shfs_type(file) != SHINODE_FILE)
    return (SHERR_IO);

  head_buff = shbuf_init();
  err = shfs_rev_ref_read(file, "tag", "BASE", head_buff);
  if (err)
    return (err);

  err = SHERR_NOENT; /* ret'd when no matching revision found */
  out_buff = shbuf_init();
  delta_buff = shbuf_init();

  /* search BASE chain for revision -- applying each revision's patch. */
  rev = shfs_rev_tag_resolve(file, "BASE");
  while (rev) {
    if (shkey_cmp(shfs_token(rev), shfs_token(i_rev))) {
      /* found revision in branch chain. */
      shbuf_append(head_buff, buff);
      err = 0;
      break;
    }

    shbuf_clear(delta_buff);
    err = shfs_rev_delta_read(rev, delta_buff);
    if (err)
      break;

/* DEBUG: TODO: merge together deltas to reduce performance over-head */
    shbuf_clear(out_buff);
    err = shpatch(head_buff, delta_buff, out_buff); 
    if (err)
      break;

    shbuf_clear(head_buff);
    shbuf_append(out_buff, head_buff);

    rev = shfs_rev_prev(rev);
  }

  shbuf_free(&head_buff);
  shbuf_free(&out_buff);
  shbuf_free(&delta_buff);
  return (err);
}
Esempio n. 24
0
/**
 * @see shsig_shr_sign()
 */
int shcert_sign(shcert_t *cert, shcert_t *parent)
{
  shkey_t *key;
  unsigned char *enc_data;
  size_t enc_len;
  int err;

  if (!parent)
    return (SHERR_INVAL);

  if (!(parent->cert_flag & SHCERT_CERT_SIGN)) {
    /* parent certificate lacks ability to sign. */
    return (SHERR_INVAL);
  }

  /* assign issuer's 128-bit serial number (regardless of algorythm)  */
  memcpy(cert->cert_iss.ent_ser, parent->cert_sub.ent_ser, 16);

  if (cert->cert_sub.ent_sig.sig_key.alg == SHKEY_ALG_ECDSA) {
    shkey_t *pub_key = &cert->cert_sub.ent_sig.sig_key;
    shkey_t *priv_key;
    shkey_t *seed_key;
    shpeer_t *peer;
    char sig_r[256];
    char sig_s[256];
    char *hex_data;
    unsigned char data[256];
    int data_len;


    /* fill in parent signature */
    memcpy(&cert->cert_iss.ent_sig, &parent->cert_sub.ent_sig, sizeof(shsig_t));

    peer = shpeer_init(NULL, NULL);
    seed_key = shpeer_kpriv(peer);
    priv_key = shecdsa_key_priv(shkey_hex(seed_key));
    shpeer_free(&peer);

    pub_key = shecdsa_key_pub(priv_key);
    memcpy(&cert->cert_sub.ent_sig.sig_key, pub_key, sizeof(shkey_t));

    if ((parent->cert_flag & SHCERT_CERT_NONREPUDIATION)) {
      /* must be derived from owner to preserve authenticy. */
      if (!shkey_cmp(&cert->cert_sub.ent_sig.sig_key, 
            &cert->cert_iss.ent_sig.sig_key)) {
        return (SHERR_ACCESS);
      }
    }

    hex_data = shkey_hex(&cert->cert_iss.ent_sig.sig_key);
    data_len = strlen(hex_data) / 2;
    memset(data, 0, sizeof(data));
    hex2bin(data, hex_data, data_len);

    shecdsa_sign(priv_key, sig_r, sig_s, data, data_len);
    strcpy(cert->cert_sub.ent_sig.key.ecdsa.sig_r, sig_r);
    strcpy(cert->cert_sub.ent_sig.key.ecdsa.sig_s, sig_s);
    cert->cert_sub.ent_len = data_len;

    shkey_free(&pub_key);
    shkey_free(&priv_key);
  } else {
    err = shencode((char *)&parent->cert_sub.ent_sig.sig_key, sizeof(shkey_t),
      &enc_data, &enc_len, &parent->cert_iss.ent_sig.sig_key);
    if (err)
      return (err);

    key = shkey_bin(enc_data, enc_len);
    free(enc_data);
    memcpy(&cert->cert_sub.ent_sig.sig_key, key, sizeof(shkey_t));
    cert->cert_sub.ent_len = enc_len;
    shkey_free(&key);
  }

  cert->cert_flag |= SHCERT_CERT_CHAIN;
  cert->cert_flag |= parent->cert_flag; /* inherit parent's attributes */
  cert->cert_sub.ent_sig.sig_key.alg = parent->cert_sub.ent_sig.sig_key.alg;

  strcpy(cert->cert_iss.ent_name, parent->cert_sub.ent_name); 
  cert->cert_iss.ent_sig.sig_stamp = parent->cert_sub.ent_sig.sig_stamp;
  cert->cert_iss.ent_sig.sig_expire = parent->cert_sub.ent_sig.sig_expire;
  cert->cert_iss.ent_len = parent->cert_sub.ent_len;


  return (0);
}
Esempio n. 25
0
int sharedaemon_bcast_recv(void)
{
    struct sockaddr_in addr;
    socklen_t addr_len;
    struct timeval to;
    fd_set read_set;
    shpeer_t *peer;
    char dgram[512];
    ssize_t r_len;
    int err;

    err = bcast_recv_init();
    if (err) {
        return (err);
    }

    FD_ZERO(&read_set);
    FD_SET(_bcast_recv_fd, &read_set);

    /* nonblocking read */
    memset(&to, 0, sizeof(to));
    err = select(_bcast_recv_fd+1, &read_set, NULL, NULL, &to);
    if (err < 0) {
        return (-errno);
    }
    if (err == 0) {
//fprintf(stderr, "\rWaiting for select(_bcast_recv_fd)..");
//fflush(stderr);
        return (0); /* nothing to read */
    }

    addr_len = sizeof(addr);
    memset(&addr, 0, addr_len);
    r_len = recvfrom(_bcast_recv_fd,
                     dgram, sizeof dgram, 0, &addr, &addr_len);
    if (r_len < 0) {
        fprintf(stderr, "DEBUG: %d = recvfrom()\n", r_len);
        return (-errno);
    }

    /* and who are you? */
    if (r_len < sizeof(shpeer_t)) {
        fprintf(stderr, "DEBUG: <%d bytes> pending..\n", r_len);
        return (SHERR_INVAL);
    }

#if 0
    now = shtime();
    tx = (tx_t *)dgram;
    if (shtime_after(tx->tx_stamp, now) ||
            shtime_before(tx->tx_stamp, shtime_adj(now, -BROADCAST_TIMEOUT))) {
        /* broadcast message must indicate sane time-frame. */
        return (SHERR_TIME);
    }

    switch (tx->tx_op) {
    case TX_PEER:
        peer_tx = (tx_peer_t *)dgram;
        if (0 != shkey_cmp(&tx->tx_peer, shpeer_kpriv(&peer_tx->peer)))
            return (SHERR_INVAL); /* only accept self-referencing broadcast */
    }
#endif


    /* share-daemon broadcasting it's peer address. */
    peer = (shpeer_t *)dgram;

    if (!shkey_cmp(shpeer_kpub(sharedaemon_peer()), shpeer_kpub(peer))) {
        /* this is not a shared peer */
        return (0); /* all done */
    }

    if (!shkey_cmp(shpeer_kpub(sharedaemon_peer()), shpeer_kpub(peer))) {
        fprintf(stderr, "DEBUG: invalid key\n");
        /* this is a peer referencing ourselves. */
        //err = sharedaemon_netclient_alias(&addr);
    }



    switch (peer->type) {
    case SHNET_PEER_LOCAL:
    case SHNET_PEER_IPV4:

        /*
           memset(&addr, '\000', sizeof(struct sockaddr_in));
           memcpy(&addr, &peer_tx->peer.addr, sizeof(peer_tx->peer.addr));
           */
        fprintf(stderr, "DEBUG: received UDP broadcast with peer \"%s\"\n", shpeer_print(peer));
        fprintf(stderr, "DEBUG: received UDP broadcast for \"%s\" port %d\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
        if (!peer->addr.sin_port)
            break; /* otay */

        addr.sin_family = AF_INET;
        err = sharedaemon_netclient_conn(peer, &addr);
        if (err)
            return (err);

        break;
    }
    fprintf(stderr, "DEBUG: processed bcast recv\n");

    return (0);
}