Merge tag 'asm-generic-cleanup-5.11' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6-microblaze.git] / net / rxrpc / security.c
index 9b1fb9e..50cb5f1 100644 (file)
@@ -55,7 +55,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;
@@ -81,16 +81,17 @@ int rxrpc_init_client_conn_security(struct rxrpc_connection *conn)
        if (ret < 0)
                return ret;
 
-       token = key->payload.data[0];
-       if (!token)
-               return -EKEYREJECTED;
+       for (token = key->payload.data[0]; token; token = token->next) {
+               sec = rxrpc_security_lookup(token->security_index);
+               if (sec)
+                       goto found;
+       }
+       return -EKEYREJECTED;
 
-       sec = rxrpc_security_lookup(token->security_index);
-       if (!sec)
-               return -EKEYREJECTED;
+found:
        conn->security = sec;
 
-       ret = conn->security->init_connection_security(conn);
+       ret = conn->security->init_connection_security(conn, token);
        if (ret < 0) {
                conn->security = &rxrpc_no_security;
                return ret;
@@ -101,22 +102,16 @@ int rxrpc_init_client_conn_security(struct rxrpc_connection *conn)
 }
 
 /*
- * Find the security key for a server connection.
+ * 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",
@@ -124,35 +119,72 @@ bool rxrpc_look_up_server_security(struct rxrpc_local *local, struct rxrpc_sock
                                  RX_INVALID_OPERATION, EKEYREJECTED);
                skb->mark = RXRPC_SKB_MARK_REJECT_ABORT;
                skb->priority = RX_INVALID_OPERATION;
-               return false;
+               return NULL;
        }
 
-       if (sp->hdr.securityIndex == RXRPC_SECURITY_NONE)
-               goto out;
-
-       if (!rx->securities) {
+       if (sp->hdr.securityIndex != RXRPC_SECURITY_NONE &&
+           !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;
+               skb->priority = sec->no_key_abort;
+               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);
+
+       rcu_read_lock();
+
+       rx = rcu_dereference(conn->params.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;
+       rcu_read_unlock();
+       return key;
 }