diff options
Diffstat (limited to 'net/rxrpc/security.c')
| -rw-r--r-- | net/rxrpc/security.c | 164 |
1 files changed, 108 insertions, 56 deletions
diff --git a/net/rxrpc/security.c b/net/rxrpc/security.c index 9b1fb9ed0717..2bfbf2b2bb37 100644 --- a/net/rxrpc/security.c +++ b/net/rxrpc/security.c @@ -20,6 +20,9 @@ static const struct rxrpc_security *rxrpc_security_types[] = { #ifdef CONFIG_RXKAD [RXRPC_SECURITY_RXKAD] = &rxkad, #endif +#ifdef CONFIG_RXGK + [RXRPC_SECURITY_YFS_RXGK] = &rxgk_yfs, +#endif }; int __init rxrpc_init_security(void) @@ -55,7 +58,7 @@ void rxrpc_exit_security(void) /* * look up an rxrpc security module */ -static const struct rxrpc_security *rxrpc_security_lookup(u8 security_index) +const struct rxrpc_security *rxrpc_security_lookup(u8 security_index) { if (security_index >= ARRAY_SIZE(rxrpc_security_types)) return NULL; @@ -63,96 +66,145 @@ static const struct rxrpc_security *rxrpc_security_lookup(u8 security_index) } /* - * initialise the security on a client connection + * Initialise the security on a client call. */ -int rxrpc_init_client_conn_security(struct rxrpc_connection *conn) +int rxrpc_init_client_call_security(struct rxrpc_call *call) { - const struct rxrpc_security *sec; + const struct rxrpc_security *sec = &rxrpc_no_security; struct rxrpc_key_token *token; - struct key *key = conn->params.key; + struct key *key = call->key; int ret; - _enter("{%d},{%x}", conn->debug_id, key_serial(key)); - if (!key) - return 0; + goto found; ret = key_validate(key); if (ret < 0) return ret; - token = key->payload.data[0]; - if (!token) - return -EKEYREJECTED; - - sec = rxrpc_security_lookup(token->security_index); - if (!sec) - return -EKEYREJECTED; - conn->security = sec; - - ret = conn->security->init_connection_security(conn); - if (ret < 0) { - conn->security = &rxrpc_no_security; - return ret; + for (token = key->payload.data[0]; token; token = token->next) { + sec = rxrpc_security_lookup(token->security_index); + if (sec) + goto found; } + return -EKEYREJECTED; - _leave(" = 0"); +found: + call->security = sec; + call->security_ix = sec->security_index; return 0; } /* - * Find the security key for a server connection. + * initialise the security on a client connection + */ +int rxrpc_init_client_conn_security(struct rxrpc_connection *conn) +{ + struct rxrpc_key_token *token; + struct key *key = conn->key; + int ret = 0; + + _enter("{%d},{%x}", conn->debug_id, key_serial(key)); + + for (token = key->payload.data[0]; token; token = token->next) { + if (token->security_index == conn->security->security_index) + goto found; + } + return -EKEYREJECTED; + +found: + mutex_lock(&conn->security_lock); + if (conn->state == RXRPC_CONN_CLIENT_UNSECURED) { + ret = conn->security->init_connection_security(conn, token); + if (ret == 0) { + spin_lock_irq(&conn->state_lock); + if (conn->state == RXRPC_CONN_CLIENT_UNSECURED) + conn->state = RXRPC_CONN_CLIENT; + spin_unlock_irq(&conn->state_lock); + } + } + mutex_unlock(&conn->security_lock); + return ret; +} + +/* + * Set the ops a server connection. */ -bool rxrpc_look_up_server_security(struct rxrpc_local *local, struct rxrpc_sock *rx, - const struct rxrpc_security **_sec, - struct key **_key, - struct sk_buff *skb) +const struct rxrpc_security *rxrpc_get_incoming_security(struct rxrpc_sock *rx, + struct sk_buff *skb) { const struct rxrpc_security *sec; struct rxrpc_skb_priv *sp = rxrpc_skb(skb); - key_ref_t kref = NULL; - char kdesc[5 + 1 + 3 + 1]; _enter(""); - sprintf(kdesc, "%u:%u", sp->hdr.serviceId, sp->hdr.securityIndex); - sec = rxrpc_security_lookup(sp->hdr.securityIndex); if (!sec) { - trace_rxrpc_abort(0, "SVS", - sp->hdr.cid, sp->hdr.callNumber, sp->hdr.seq, - RX_INVALID_OPERATION, EKEYREJECTED); - skb->mark = RXRPC_SKB_MARK_REJECT_ABORT; - skb->priority = RX_INVALID_OPERATION; - return false; + rxrpc_direct_conn_abort(skb, rxrpc_abort_unsupported_security, + RX_INVALID_OPERATION, -EKEYREJECTED); + return NULL; } - if (sp->hdr.securityIndex == RXRPC_SECURITY_NONE) - goto out; - - if (!rx->securities) { - trace_rxrpc_abort(0, "SVR", - sp->hdr.cid, sp->hdr.callNumber, sp->hdr.seq, - RX_INVALID_OPERATION, EKEYREJECTED); - skb->mark = RXRPC_SKB_MARK_REJECT_ABORT; - skb->priority = RX_INVALID_OPERATION; - return false; + if (sp->hdr.securityIndex != RXRPC_SECURITY_NONE && + !rx->securities) { + rxrpc_direct_conn_abort(skb, rxrpc_abort_no_service_key, + sec->no_key_abort, -EKEYREJECTED); + return NULL; } + return sec; +} + +/* + * Find the security key for a server connection. + */ +struct key *rxrpc_look_up_server_security(struct rxrpc_connection *conn, + struct sk_buff *skb, + u32 kvno, u32 enctype) +{ + struct rxrpc_skb_priv *sp = rxrpc_skb(skb); + struct rxrpc_sock *rx; + struct key *key = ERR_PTR(-EKEYREJECTED); + key_ref_t kref = NULL; + char kdesc[5 + 1 + 3 + 1 + 12 + 1 + 12 + 1]; + int ret; + + _enter(""); + + if (enctype) + sprintf(kdesc, "%u:%u:%u:%u", + sp->hdr.serviceId, sp->hdr.securityIndex, kvno, enctype); + else if (kvno) + sprintf(kdesc, "%u:%u:%u", + sp->hdr.serviceId, sp->hdr.securityIndex, kvno); + else + sprintf(kdesc, "%u:%u", + sp->hdr.serviceId, sp->hdr.securityIndex); + + read_lock(&conn->local->services_lock); + + rx = conn->local->service; + if (!rx) + goto out; + /* look through the service's keyring */ kref = keyring_search(make_key_ref(rx->securities, 1UL), &key_type_rxrpc_s, kdesc, true); if (IS_ERR(kref)) { - trace_rxrpc_abort(0, "SVK", - sp->hdr.cid, sp->hdr.callNumber, sp->hdr.seq, - sec->no_key_abort, EKEYREJECTED); - skb->mark = RXRPC_SKB_MARK_REJECT_ABORT; - skb->priority = sec->no_key_abort; - return false; + key = ERR_CAST(kref); + goto out; + } + + key = key_ref_to_ptr(kref); + + ret = key_validate(key); + if (ret < 0) { + key_put(key); + key = ERR_PTR(ret); + goto out; } out: - *_sec = sec; - *_key = key_ref_to_ptr(kref); - return true; + read_unlock(&conn->local->services_lock); + return key; } |
