/** * urf_session_checker_inhibit: **/ guint urf_session_checker_inhibit (UrfSessionChecker *logind, const char *bus_name, const char *reason) { UrfLogindPrivate *priv = logind->priv; UrfInhibitor *inhibitor; g_return_val_if_fail (priv->proxy != NULL, 0); inhibitor = find_inhibitor_by_bus_name (logind, bus_name); if (inhibitor) return inhibitor->cookie; inhibitor = g_new0 (UrfInhibitor, 1); inhibitor->session_id = get_session_id (logind, bus_name); if (inhibitor->session_id == NULL) { g_free (inhibitor); return 0; } inhibitor->reason = g_strdup (reason); inhibitor->bus_name = g_strdup (bus_name); inhibitor->cookie = generate_unique_cookie (logind); priv->inhibitors = g_list_prepend (priv->inhibitors, inhibitor); logind->priv->inhibit = is_inhibited (logind); g_debug ("Inhibit: %s for %s", bus_name, reason); return inhibitor->cookie; }
/* accept and process request form local client */ void process_client_request(int fd_un2) { int len, len_toreceive, len_received, len_tosend, len_sent; int rc, fd_in = 0; CLI_REQUEST creq; CLI_RESPONSE cresp; SRV_REQUEST sreq; SRV_RESPONSE sresp; SRV_MESSAGE smsg; char buf[2048]; char keyid[MAX_TAG_LEN + MAX_HOST_LEN + 10]; BIGNUM *bn_base = NULL, *bn_prime = NULL, *bn_private = NULL; unsigned char* public = NULL; int public_len; unsigned char* secret_key = NULL; int secret_key_len; memset(&cresp, 0, sizeof(cresp)); memset(&sreq, 0, sizeof(sreq)); memset(&smsg, 0, sizeof(smsg)); /* receive request - we can expect at least 7 first bytes to receive */ len = recv(fd_un2, buf, 7, 0); if (len < 0) { output(LOG_ERR, "recv failed. %s", strerror(errno)); cresp.status = MK_STATUS(SCOPE_HOST, ERR_COMM); goto send; } else if (!len) return; len_received = len; len_toreceive = get_der_seq_size(buf); if (len_toreceive > sizeof(buf)) { output(LOG_ERR, "packet sent by client is too big"); cresp.status = MK_STATUS(SCOPE_CLIENT, ERR_MALFORMED); goto send; } /* get the rest */ while (len_toreceive > len_received) { len = len_toreceive - len_received; len = recv(fd_un2, &buf[len_received], len, 0); if (len < 0) { output(LOG_ERR, "recv failed. %s", strerror(errno)); cresp.status = MK_STATUS(SCOPE_HOST, ERR_COMM); goto send; } else if (!len) return; len_received += len; } /* decode request message */ rc = decode_client_request(buf, len_received, &creq); if (rc) { cresp.status = MK_STATUS(SCOPE_CLIENT, rc); goto send; } /* check if parameters, flags are valid */ if (creq.version != CURRENT_PROTOCOL_VERSION) { output(LOG_ERR, "unsupported protocol version %d", creq.version); cresp.status = MK_STATUS(SCOPE_CLIENT, ERR_PROTOCOL); goto send; } if (check_flag_validity(creq.flags)) { output(LOG_ERR, "not allowed option combination"); cresp.status = MK_STATUS(SCOPE_CLIENT, ERR_INVALID_PARAM); goto send; } if (creq.reqType == CRT_ENUM_KEYS) { cresp.status = STATUS_SUCCESS; goto send; } else if (creq.reqType == CRT_REQUEST_KEY && (!creq.keyLen || creq.keyLen > MAX_KEY_LEN)) { output(LOG_ERR, "invalid size of requested key: %d", creq.keyLen); cresp.status = MK_STATUS(SCOPE_CLIENT, ERR_INVALID_PARAM); goto send; } /* make keyid */ sprintf(keyid, "%s@%s", creq.tag, creq.peer); /* process request */ if (creq.reqType == CRT_DELETE_KEY) { /* check for a key in database and delete it */ if (keydb_exists(keyid)) { rc = keydb_delete(keyid); if (rc) { output(LOG_ERR, "keydb_delete failed. %s", strerror(errno)); cresp.status = MK_STATUS(SCOPE_HOST, ERR_INTERNAL); } } else { output(LOG_ERR, "requested key does not exist: '%s'", keyid); cresp.status = MK_STATUS(SCOPE_HOST, ERR_KEY_NOT_EXISTS); } } /* here we block and get requested key */ else if (creq.flags & FLAG_INIT_KEY) { struct sockaddr_in peer_addr; char addr_accept[] = "0123456789."; PEER_ENTRY* pe; /* locate and check the peer */ pe = find_peer(creq.peer); if (!pe) { output(LOG_ERR, "peer '%s' is not available", creq.peer); cresp.status = MK_STATUS(SCOPE_HOST, ERR_NOT_AVAILABLE); goto send; } else if (!pe->allow) { output(LOG_ERR, "access denied for peer '%s'", creq.peer); cresp.status = MK_STATUS(SCOPE_HOST, ERR_ACCESS_DENIED); goto send; } /* generate secret, calculate public value */ rc = dh_init_group_params(conf_dh_group, &bn_prime, &bn_base); if (rc) { output(LOG_ERR, "dh_init_group_params failed"); cresp.status = MK_STATUS(SCOPE_HOST, rc); goto send; } DUMP_BN(bn_prime, "prime "); DUMP_BN(bn_base, "base "); rc = dh_gen_private_public(conf_dh_group, bn_prime, bn_base, &bn_private, &public, &public_len); if (rc) { output(LOG_ERR, "dh_gen_private_public failed"); cresp.status = MK_STATUS(SCOPE_HOST, rc); goto send; } DUMP_BN(bn_private, "priv-i"); DUMP_BIN(public, public_len, "publ-i"); /* fill-in request */ sreq.cookie = generate_unique_cookie(); sreq.keyLen = creq.keyLen; strncpy(sreq.tag, creq.tag, sizeof(sreq.tag)); strncpy(sreq.host, conf_host, sizeof(sreq.host)); strncpy(sreq.expires, creq.expires, sizeof(sreq.expires)); sreq.dhGroup = conf_dh_group; sreq.dhPublic_len = public_len; memcpy(sreq.dhPublic, public, public_len); smsg.tbsMsg_len = sizeof(smsg.tbsMsg); rc = encode_server_request(&sreq, smsg.tbsMsg, &smsg.tbsMsg_len); if (rc) { cresp.status = MK_STATUS(SCOPE_HOST, rc); goto send; } /* fill-in request message */ smsg.version = CURRENT_PROTOCOL_VERSION; /* sign request if required */ if (pe->auth != AUTH_NONE) { rc = sign_message(pe, smsg.tbsMsg, smsg.tbsMsg_len, smsg.sigAlg, &smsg.sigAlg_len, smsg.sig, &smsg.sig_len); if (rc) { cresp.status = MK_STATUS(SCOPE_HOST, rc); goto send; } } /* encode message */ len = sizeof(buf); rc = encode_server_message(&smsg, buf, &len); if (rc) { cresp.status = MK_STATUS(SCOPE_HOST, rc); goto send; } /* get peer id & address, connect to socket and send the message */ /* is it ip address? */ if (strspn(creq.peer, addr_accept) == strlen(creq.peer)) { if (!inet_aton(creq.peer, &(peer_addr.sin_addr))) { output(LOG_ERR, "inet_aton failed"); cresp.status = MK_STATUS(SCOPE_HOST, ERR_COMM); goto send; } } /* resolve dns */ else { struct hostent* h = gethostbyname(creq.peer); if (!h) { output(LOG_ERR, "gethostbyname failed"); cresp.status = MK_STATUS(SCOPE_HOST, ERR_COMM); goto send; } peer_addr.sin_addr = *((struct in_addr*)h->h_addr); } peer_addr.sin_family = AF_INET; peer_addr.sin_port = htons(creq.port ? creq.port : DEFAULT_PORT); memset(peer_addr.sin_zero, 0, sizeof(peer_addr.sin_zero)); fd_in = socket(AF_INET, SOCK_STREAM, 0); if (!fd_in) { output(LOG_ERR, "socket failed. %s", strerror(errno)); cresp.status = MK_STATUS(SCOPE_HOST, ERR_COMM); goto send; } rc = connect(fd_in, (struct sockaddr*)&peer_addr, sizeof(struct sockaddr)); if (rc == -1) { output(LOG_ERR, "connect failed. %s", strerror(errno)); cresp.status = MK_STATUS(SCOPE_HOST, ERR_COMM); goto send; } /* send request */ len_sent = 0; len_tosend = len; while (len_tosend > len_sent) { len = len_tosend - len_sent; len = send(fd_in, &buf[len_sent], len, 0); if (len < 0) { output(LOG_ERR, "send failed/connection closed by peer"); cresp.status = MK_STATUS(SCOPE_HOST, ERR_COMM); goto send; } len_sent += len; } memset(&smsg, 0, sizeof(smsg)); /* receive response - we can expect at least 14 bytes to receive */ len = recv(fd_in, buf, 14, 0); if (len <= 0) { output(LOG_ERR, "recv failed/connection closed by peer"); cresp.status = MK_STATUS(SCOPE_HOST, ERR_COMM); goto send; } len_received = len; len_toreceive = get_der_seq_size(buf); assert(len_toreceive <= sizeof(buf)); if (len_toreceive > sizeof(buf)) { output(LOG_ERR, "packet sent by peer is too big"); cresp.status = MK_STATUS(SCOPE_PEER, ERR_MALFORMED); goto send; } /* get the rest */ while (len_toreceive > len_received) { len = len_toreceive - len_received; len = recv(fd_in, &buf[len_received], len, 0); if (len < 0) { output(LOG_ERR, "recv failed/connection closed by peer"); cresp.status = MK_STATUS(SCOPE_HOST, ERR_COMM); goto send; } len_received += len; } close(fd_in); fd_in = 0; /* decode response message */ rc = decode_server_message(buf, len_received, &smsg); if (rc) { cresp.status = MK_STATUS(SCOPE_HOST, rc); goto send; } /* sanity check */ if (smsg.version != CURRENT_PROTOCOL_VERSION) { output(LOG_ERR, "unsupported protocol version %d", smsg.version); cresp.status = MK_STATUS(SCOPE_PEER, ERR_PROTOCOL); goto send; } /* verify signature if required */ if (smsg.sigAlg_len && smsg.sig_len) { rc = verify_signature(pe, smsg.tbsMsg, smsg.tbsMsg_len, smsg.sigAlg, smsg.sigAlg_len, smsg.sig, smsg.sig_len); if (rc) { cresp.status = MK_STATUS(SCOPE_HOST, rc); goto send; } } else if (pe->auth != AUTH_NONE) { output(LOG_ERR, "response is not signed"); cresp.status = MK_STATUS(SCOPE_PEER, ERR_SIG_VERIFY); goto send; } /* decode response */ rc = decode_server_response(smsg.tbsMsg, smsg.tbsMsg_len, &sresp); if (rc) { cresp.status = MK_STATUS(SCOPE_HOST, rc); goto send; } if (GET_ERR(sresp.status)) { output(LOG_ERR, "peer returned status 0x%0.2hx", sresp.status); cresp.status = MK_STATUS(SCOPE_PEER, GET_ERR(sresp.status)); goto send; } /* calculate shared secret, make a requested key */ rc = dh_get_secret(sresp.dhPublic, sresp.dhPublic_len, bn_private, bn_prime, &secret_key, &secret_key_len); if (rc) { output(LOG_ERR, "dh_get_secret failed"); cresp.status = MK_STATUS(SCOPE_HOST, rc); goto send; } DUMP_BIN(sresp.dhPublic, sresp.dhPublic_len, "publ-r"); DUMP_BIN(secret_key, secret_key_len, "secr-i"); assert(secret_key_len >= BITS_TO_BYTES(creq.keyLen)); /* store a key to database */ if (creq.flags & FLAG_STORE_KEY) { char kval_buf[KEY_VAL_SIZE + MAX_KEY_LEN]; PKEY_VAL pkey_val = (PKEY_VAL)kval_buf; pkey_val->expires = gentime_to_time_t(creq.expires); if (pkey_val->expires == -1) { output(LOG_ERR, "cannot convert time value %s", creq.expires); cresp.status = MK_STATUS(SCOPE_HOST, ERR_INVALID_PARAM); goto send; } pkey_val->key_len = creq.keyLen; memcpy(pkey_val->key, secret_key, BITS_TO_BYTES(pkey_val->key_len)); rc = keydb_store(keyid, kval_buf, sizeof(KEY_VAL) + BITS_TO_BYTES(pkey_val->key_len)); if (rc) { output(LOG_ERR, "keydb_store failed. %s", strerror(errno)); cresp.status = MK_STATUS(SCOPE_HOST, ERR_INTERNAL); goto send; } output(LOG_INFO, "new key '%s' (%dbits) added, validity: %s", keyid, pkey_val->key_len, ctime(&pkey_val->expires)); } cresp.keyLen = creq.keyLen; memcpy(cresp.key, secret_key, BITS_TO_BYTES(cresp.keyLen)); cresp.status = STATUS_SUCCESS; } else {