diff options
-rw-r--r-- | include/net/sctp/auth.h | 16 | ||||
-rw-r--r-- | include/net/sctp/ulpevent.h | 4 | ||||
-rw-r--r-- | include/net/sctp/user.h | 90 | ||||
-rw-r--r-- | net/sctp/auth.c | 193 | ||||
-rw-r--r-- | net/sctp/sm_statefuns.c | 13 | ||||
-rw-r--r-- | net/sctp/socket.c | 304 | ||||
-rw-r--r-- | net/sctp/ulpevent.c | 37 |
7 files changed, 657 insertions, 0 deletions
diff --git a/include/net/sctp/auth.h b/include/net/sctp/auth.h index 10c8010552ff..4945954a16af 100644 --- a/include/net/sctp/auth.h +++ b/include/net/sctp/auth.h | |||
@@ -43,6 +43,7 @@ | |||
43 | struct sctp_endpoint; | 43 | struct sctp_endpoint; |
44 | struct sctp_association; | 44 | struct sctp_association; |
45 | struct sctp_authkey; | 45 | struct sctp_authkey; |
46 | struct sctp_hmacalgo; | ||
46 | 47 | ||
47 | /* | 48 | /* |
48 | * Define a generic struct that will hold all the info | 49 | * Define a generic struct that will hold all the info |
@@ -109,4 +110,19 @@ int sctp_auth_recv_cid(sctp_cid_t chunk, const struct sctp_association *asoc); | |||
109 | void sctp_auth_calculate_hmac(const struct sctp_association *asoc, | 110 | void sctp_auth_calculate_hmac(const struct sctp_association *asoc, |
110 | struct sk_buff *skb, | 111 | struct sk_buff *skb, |
111 | struct sctp_auth_chunk *auth, gfp_t gfp); | 112 | struct sctp_auth_chunk *auth, gfp_t gfp); |
113 | |||
114 | /* API Helpers */ | ||
115 | int sctp_auth_ep_add_chunkid(struct sctp_endpoint *ep, __u8 chunk_id); | ||
116 | int sctp_auth_ep_set_hmacs(struct sctp_endpoint *ep, | ||
117 | struct sctp_hmacalgo *hmacs); | ||
118 | int sctp_auth_set_key(struct sctp_endpoint *ep, | ||
119 | struct sctp_association *asoc, | ||
120 | struct sctp_authkey *auth_key); | ||
121 | int sctp_auth_set_active_key(struct sctp_endpoint *ep, | ||
122 | struct sctp_association *asoc, | ||
123 | __u16 key_id); | ||
124 | int sctp_auth_del_key_id(struct sctp_endpoint *ep, | ||
125 | struct sctp_association *asoc, | ||
126 | __u16 key_id); | ||
127 | |||
112 | #endif | 128 | #endif |
diff --git a/include/net/sctp/ulpevent.h b/include/net/sctp/ulpevent.h index de88ed5b0ba6..922a151eb93c 100644 --- a/include/net/sctp/ulpevent.h +++ b/include/net/sctp/ulpevent.h | |||
@@ -128,6 +128,10 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc, | |||
128 | struct sctp_chunk *chunk, | 128 | struct sctp_chunk *chunk, |
129 | gfp_t gfp); | 129 | gfp_t gfp); |
130 | 130 | ||
131 | struct sctp_ulpevent *sctp_ulpevent_make_authkey( | ||
132 | const struct sctp_association *asoc, __u16 key_id, | ||
133 | __u32 indication, gfp_t gfp); | ||
134 | |||
131 | void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event, | 135 | void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event, |
132 | struct msghdr *); | 136 | struct msghdr *); |
133 | __u16 sctp_ulpevent_get_notification_type(const struct sctp_ulpevent *event); | 137 | __u16 sctp_ulpevent_get_notification_type(const struct sctp_ulpevent *event); |
diff --git a/include/net/sctp/user.h b/include/net/sctp/user.h index 6d2b57758cca..00848b641f59 100644 --- a/include/net/sctp/user.h +++ b/include/net/sctp/user.h | |||
@@ -103,6 +103,21 @@ enum sctp_optname { | |||
103 | #define SCTP_PARTIAL_DELIVERY_POINT SCTP_PARTIAL_DELIVERY_POINT | 103 | #define SCTP_PARTIAL_DELIVERY_POINT SCTP_PARTIAL_DELIVERY_POINT |
104 | SCTP_MAX_BURST, /* Set/Get max burst */ | 104 | SCTP_MAX_BURST, /* Set/Get max burst */ |
105 | #define SCTP_MAX_BURST SCTP_MAX_BURST | 105 | #define SCTP_MAX_BURST SCTP_MAX_BURST |
106 | SCTP_AUTH_CHUNK, /* Set only: add a chunk type to authenticat */ | ||
107 | #define SCTP_AUTH_CHUNK SCTP_AUTH_CHUNK | ||
108 | SCTP_HMAC_IDENT, | ||
109 | #define SCTP_HMAC_IDENT SCTP_HMAC_IDENT | ||
110 | SCTP_AUTH_KEY, | ||
111 | #define SCTP_AUTH_KEY SCTP_AUTH_KEY | ||
112 | SCTP_AUTH_ACTIVE_KEY, | ||
113 | #define SCTP_AUTH_ACTIVE_KEY SCTP_AUTH_ACTIVE_KEY | ||
114 | SCTP_AUTH_DELETE_KEY, | ||
115 | #define SCTP_AUTH_DELETE_KEY SCTP_AUTH_DELETE_KEY | ||
116 | SCTP_PEER_AUTH_CHUNKS, /* Read only */ | ||
117 | #define SCTP_PEER_AUTH_CHUNKS SCTP_PEER_AUTH_CHUNKS | ||
118 | SCTP_LOCAL_AUTH_CHUNKS, /* Read only */ | ||
119 | #define SCTP_LOCAL_AUTH_CHUNKS SCTP_LOCAL_AUTH_CHUNKS | ||
120 | |||
106 | 121 | ||
107 | /* Internal Socket Options. Some of the sctp library functions are | 122 | /* Internal Socket Options. Some of the sctp library functions are |
108 | * implemented using these socket options. | 123 | * implemented using these socket options. |
@@ -370,6 +385,19 @@ struct sctp_pdapi_event { | |||
370 | 385 | ||
371 | enum { SCTP_PARTIAL_DELIVERY_ABORTED=0, }; | 386 | enum { SCTP_PARTIAL_DELIVERY_ABORTED=0, }; |
372 | 387 | ||
388 | struct sctp_authkey_event { | ||
389 | __u16 auth_type; | ||
390 | __u16 auth_flags; | ||
391 | __u32 auth_length; | ||
392 | __u16 auth_keynumber; | ||
393 | __u16 auth_altkeynumber; | ||
394 | __u32 auth_indication; | ||
395 | sctp_assoc_t auth_assoc_id; | ||
396 | }; | ||
397 | |||
398 | enum { SCTP_AUTH_NEWKEY = 0, }; | ||
399 | |||
400 | |||
373 | /* | 401 | /* |
374 | * Described in Section 7.3 | 402 | * Described in Section 7.3 |
375 | * Ancillary Data and Notification Interest Options | 403 | * Ancillary Data and Notification Interest Options |
@@ -405,6 +433,7 @@ union sctp_notification { | |||
405 | struct sctp_shutdown_event sn_shutdown_event; | 433 | struct sctp_shutdown_event sn_shutdown_event; |
406 | struct sctp_adaptation_event sn_adaptation_event; | 434 | struct sctp_adaptation_event sn_adaptation_event; |
407 | struct sctp_pdapi_event sn_pdapi_event; | 435 | struct sctp_pdapi_event sn_pdapi_event; |
436 | struct sctp_authkey_event sn_authkey_event; | ||
408 | }; | 437 | }; |
409 | 438 | ||
410 | /* Section 5.3.1 | 439 | /* Section 5.3.1 |
@@ -421,6 +450,7 @@ enum sctp_sn_type { | |||
421 | SCTP_SHUTDOWN_EVENT, | 450 | SCTP_SHUTDOWN_EVENT, |
422 | SCTP_PARTIAL_DELIVERY_EVENT, | 451 | SCTP_PARTIAL_DELIVERY_EVENT, |
423 | SCTP_ADAPTATION_INDICATION, | 452 | SCTP_ADAPTATION_INDICATION, |
453 | SCTP_AUTHENTICATION_EVENT, | ||
424 | }; | 454 | }; |
425 | 455 | ||
426 | /* Notification error codes used to fill up the error fields in some | 456 | /* Notification error codes used to fill up the error fields in some |
@@ -539,6 +569,54 @@ struct sctp_paddrparams { | |||
539 | __u32 spp_flags; | 569 | __u32 spp_flags; |
540 | } __attribute__((packed, aligned(4))); | 570 | } __attribute__((packed, aligned(4))); |
541 | 571 | ||
572 | /* | ||
573 | * 7.1.18. Add a chunk that must be authenticated (SCTP_AUTH_CHUNK) | ||
574 | * | ||
575 | * This set option adds a chunk type that the user is requesting to be | ||
576 | * received only in an authenticated way. Changes to the list of chunks | ||
577 | * will only effect future associations on the socket. | ||
578 | */ | ||
579 | struct sctp_authchunk { | ||
580 | __u8 sauth_chunk; | ||
581 | }; | ||
582 | |||
583 | /* | ||
584 | * 7.1.19. Get or set the list of supported HMAC Identifiers (SCTP_HMAC_IDENT) | ||
585 | * | ||
586 | * This option gets or sets the list of HMAC algorithms that the local | ||
587 | * endpoint requires the peer to use. | ||
588 | */ | ||
589 | struct sctp_hmacalgo { | ||
590 | __u16 shmac_num_idents; | ||
591 | __u16 shmac_idents[]; | ||
592 | }; | ||
593 | |||
594 | /* | ||
595 | * 7.1.20. Set a shared key (SCTP_AUTH_KEY) | ||
596 | * | ||
597 | * This option will set a shared secret key which is used to build an | ||
598 | * association shared key. | ||
599 | */ | ||
600 | struct sctp_authkey { | ||
601 | sctp_assoc_t sca_assoc_id; | ||
602 | __u16 sca_keynumber; | ||
603 | __u16 sca_keylen; | ||
604 | __u8 sca_key[]; | ||
605 | }; | ||
606 | |||
607 | /* | ||
608 | * 7.1.21. Get or set the active shared key (SCTP_AUTH_ACTIVE_KEY) | ||
609 | * | ||
610 | * This option will get or set the active shared key to be used to build | ||
611 | * the association shared key. | ||
612 | */ | ||
613 | |||
614 | struct sctp_authkeyid { | ||
615 | sctp_assoc_t scact_assoc_id; | ||
616 | __u16 scact_keynumber; | ||
617 | }; | ||
618 | |||
619 | |||
542 | /* 7.1.23. Delayed Ack Timer (SCTP_DELAYED_ACK_TIME) | 620 | /* 7.1.23. Delayed Ack Timer (SCTP_DELAYED_ACK_TIME) |
543 | * | 621 | * |
544 | * This options will get or set the delayed ack timer. The time is set | 622 | * This options will get or set the delayed ack timer. The time is set |
@@ -608,6 +686,18 @@ struct sctp_status { | |||
608 | }; | 686 | }; |
609 | 687 | ||
610 | /* | 688 | /* |
689 | * 7.2.3. Get the list of chunks the peer requires to be authenticated | ||
690 | * (SCTP_PEER_AUTH_CHUNKS) | ||
691 | * | ||
692 | * This option gets a list of chunks for a specified association that | ||
693 | * the peer requires to be received authenticated only. | ||
694 | */ | ||
695 | struct sctp_authchunks { | ||
696 | sctp_assoc_t gauth_assoc_id; | ||
697 | uint8_t gauth_chunks[]; | ||
698 | }; | ||
699 | |||
700 | /* | ||
611 | * 8.3, 8.5 get all peer/local addresses in an association. | 701 | * 8.3, 8.5 get all peer/local addresses in an association. |
612 | * This parameter struct is used by SCTP_GET_PEER_ADDRS and | 702 | * This parameter struct is used by SCTP_GET_PEER_ADDRS and |
613 | * SCTP_GET_LOCAL_ADDRS socket options used internally to implement | 703 | * SCTP_GET_LOCAL_ADDRS socket options used internally to implement |
diff --git a/net/sctp/auth.c b/net/sctp/auth.c index 2a29409a38d9..781810724714 100644 --- a/net/sctp/auth.c +++ b/net/sctp/auth.c | |||
@@ -743,3 +743,196 @@ free: | |||
743 | if (free_key) | 743 | if (free_key) |
744 | sctp_auth_key_put(asoc_key); | 744 | sctp_auth_key_put(asoc_key); |
745 | } | 745 | } |
746 | |||
747 | /* API Helpers */ | ||
748 | |||
749 | /* Add a chunk to the endpoint authenticated chunk list */ | ||
750 | int sctp_auth_ep_add_chunkid(struct sctp_endpoint *ep, __u8 chunk_id) | ||
751 | { | ||
752 | struct sctp_chunks_param *p = ep->auth_chunk_list; | ||
753 | __u16 nchunks; | ||
754 | __u16 param_len; | ||
755 | |||
756 | /* If this chunk is already specified, we are done */ | ||
757 | if (__sctp_auth_cid(chunk_id, p)) | ||
758 | return 0; | ||
759 | |||
760 | /* Check if we can add this chunk to the array */ | ||
761 | param_len = ntohs(p->param_hdr.length); | ||
762 | nchunks = param_len - sizeof(sctp_paramhdr_t); | ||
763 | if (nchunks == SCTP_NUM_CHUNK_TYPES) | ||
764 | return -EINVAL; | ||
765 | |||
766 | p->chunks[nchunks] = chunk_id; | ||
767 | p->param_hdr.length = htons(param_len + 1); | ||
768 | return 0; | ||
769 | } | ||
770 | |||
771 | /* Add hmac identifires to the endpoint list of supported hmac ids */ | ||
772 | int sctp_auth_ep_set_hmacs(struct sctp_endpoint *ep, | ||
773 | struct sctp_hmacalgo *hmacs) | ||
774 | { | ||
775 | int has_sha1 = 0; | ||
776 | __u16 id; | ||
777 | int i; | ||
778 | |||
779 | /* Scan the list looking for unsupported id. Also make sure that | ||
780 | * SHA1 is specified. | ||
781 | */ | ||
782 | for (i = 0; i < hmacs->shmac_num_idents; i++) { | ||
783 | id = hmacs->shmac_idents[i]; | ||
784 | |||
785 | if (SCTP_AUTH_HMAC_ID_SHA1 == id) | ||
786 | has_sha1 = 1; | ||
787 | |||
788 | if (!sctp_hmac_list[id].hmac_name) | ||
789 | return -EOPNOTSUPP; | ||
790 | } | ||
791 | |||
792 | if (!has_sha1) | ||
793 | return -EINVAL; | ||
794 | |||
795 | memcpy(ep->auth_hmacs_list->hmac_ids, &hmacs->shmac_idents[0], | ||
796 | hmacs->shmac_num_idents * sizeof(__u16)); | ||
797 | ep->auth_hmacs_list->param_hdr.length = htons(sizeof(sctp_paramhdr_t) + | ||
798 | hmacs->shmac_num_idents * sizeof(__u16)); | ||
799 | return 0; | ||
800 | } | ||
801 | |||
802 | /* Set a new shared key on either endpoint or association. If the | ||
803 | * the key with a same ID already exists, replace the key (remove the | ||
804 | * old key and add a new one). | ||
805 | */ | ||
806 | int sctp_auth_set_key(struct sctp_endpoint *ep, | ||
807 | struct sctp_association *asoc, | ||
808 | struct sctp_authkey *auth_key) | ||
809 | { | ||
810 | struct sctp_shared_key *cur_key = NULL; | ||
811 | struct sctp_auth_bytes *key; | ||
812 | struct list_head *sh_keys; | ||
813 | int replace = 0; | ||
814 | |||
815 | /* Try to find the given key id to see if | ||
816 | * we are doing a replace, or adding a new key | ||
817 | */ | ||
818 | if (asoc) | ||
819 | sh_keys = &asoc->endpoint_shared_keys; | ||
820 | else | ||
821 | sh_keys = &ep->endpoint_shared_keys; | ||
822 | |||
823 | key_for_each(cur_key, sh_keys) { | ||
824 | if (cur_key->key_id == auth_key->sca_keynumber) { | ||
825 | replace = 1; | ||
826 | break; | ||
827 | } | ||
828 | } | ||
829 | |||
830 | /* If we are not replacing a key id, we need to allocate | ||
831 | * a shared key. | ||
832 | */ | ||
833 | if (!replace) { | ||
834 | cur_key = sctp_auth_shkey_create(auth_key->sca_keynumber, | ||
835 | GFP_KERNEL); | ||
836 | if (!cur_key) | ||
837 | return -ENOMEM; | ||
838 | } | ||
839 | |||
840 | /* Create a new key data based on the info passed in */ | ||
841 | key = sctp_auth_create_key(auth_key->sca_keylen, GFP_KERNEL); | ||
842 | if (!key) | ||
843 | goto nomem; | ||
844 | |||
845 | memcpy(key->data, &auth_key->sca_key[0], auth_key->sca_keylen); | ||
846 | |||
847 | /* If we are replacing, remove the old keys data from the | ||
848 | * key id. If we are adding new key id, add it to the | ||
849 | * list. | ||
850 | */ | ||
851 | if (replace) | ||
852 | sctp_auth_key_put(cur_key->key); | ||
853 | else | ||
854 | list_add(&cur_key->key_list, sh_keys); | ||
855 | |||
856 | cur_key->key = key; | ||
857 | sctp_auth_key_hold(key); | ||
858 | |||
859 | return 0; | ||
860 | nomem: | ||
861 | if (!replace) | ||
862 | sctp_auth_shkey_free(cur_key); | ||
863 | |||
864 | return -ENOMEM; | ||
865 | } | ||
866 | |||
867 | int sctp_auth_set_active_key(struct sctp_endpoint *ep, | ||
868 | struct sctp_association *asoc, | ||
869 | __u16 key_id) | ||
870 | { | ||
871 | struct sctp_shared_key *key; | ||
872 | struct list_head *sh_keys; | ||
873 | int found = 0; | ||
874 | |||
875 | /* The key identifier MUST correst to an existing key */ | ||
876 | if (asoc) | ||
877 | sh_keys = &asoc->endpoint_shared_keys; | ||
878 | else | ||
879 | sh_keys = &ep->endpoint_shared_keys; | ||
880 | |||
881 | key_for_each(key, sh_keys) { | ||
882 | if (key->key_id == key_id) { | ||
883 | found = 1; | ||
884 | break; | ||
885 | } | ||
886 | } | ||
887 | |||
888 | if (!found) | ||
889 | return -EINVAL; | ||
890 | |||
891 | if (asoc) { | ||
892 | asoc->active_key_id = key_id; | ||
893 | sctp_auth_asoc_init_active_key(asoc, GFP_KERNEL); | ||
894 | } else | ||
895 | ep->active_key_id = key_id; | ||
896 | |||
897 | return 0; | ||
898 | } | ||
899 | |||
900 | int sctp_auth_del_key_id(struct sctp_endpoint *ep, | ||
901 | struct sctp_association *asoc, | ||
902 | __u16 key_id) | ||
903 | { | ||
904 | struct sctp_shared_key *key; | ||
905 | struct list_head *sh_keys; | ||
906 | int found = 0; | ||
907 | |||
908 | /* The key identifier MUST NOT be the current active key | ||
909 | * The key identifier MUST correst to an existing key | ||
910 | */ | ||
911 | if (asoc) { | ||
912 | if (asoc->active_key_id == key_id) | ||
913 | return -EINVAL; | ||
914 | |||
915 | sh_keys = &asoc->endpoint_shared_keys; | ||
916 | } else { | ||
917 | if (ep->active_key_id == key_id) | ||
918 | return -EINVAL; | ||
919 | |||
920 | sh_keys = &ep->endpoint_shared_keys; | ||
921 | } | ||
922 | |||
923 | key_for_each(key, sh_keys) { | ||
924 | if (key->key_id == key_id) { | ||
925 | found = 1; | ||
926 | break; | ||
927 | } | ||
928 | } | ||
929 | |||
930 | if (!found) | ||
931 | return -EINVAL; | ||
932 | |||
933 | /* Delete the shared key */ | ||
934 | list_del_init(&key->key_list); | ||
935 | sctp_auth_shkey_free(key); | ||
936 | |||
937 | return 0; | ||
938 | } | ||
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 5aef4aafdfdc..f01b408508ff 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c | |||
@@ -3848,6 +3848,19 @@ sctp_disposition_t sctp_sf_eat_auth(const struct sctp_endpoint *ep, | |||
3848 | break; | 3848 | break; |
3849 | } | 3849 | } |
3850 | 3850 | ||
3851 | if (asoc->active_key_id != ntohs(auth_hdr->shkey_id)) { | ||
3852 | struct sctp_ulpevent *ev; | ||
3853 | |||
3854 | ev = sctp_ulpevent_make_authkey(asoc, ntohs(auth_hdr->shkey_id), | ||
3855 | SCTP_AUTH_NEWKEY, GFP_ATOMIC); | ||
3856 | |||
3857 | if (!ev) | ||
3858 | return -ENOMEM; | ||
3859 | |||
3860 | sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, | ||
3861 | SCTP_ULPEVENT(ev)); | ||
3862 | } | ||
3863 | |||
3851 | return SCTP_DISPOSITION_CONSUME; | 3864 | return SCTP_DISPOSITION_CONSUME; |
3852 | } | 3865 | } |
3853 | 3866 | ||
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 7738915011a0..f3e1a9c811ad 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c | |||
@@ -2946,6 +2946,164 @@ static int sctp_setsockopt_maxburst(struct sock *sk, | |||
2946 | return 0; | 2946 | return 0; |
2947 | } | 2947 | } |
2948 | 2948 | ||
2949 | /* | ||
2950 | * 7.1.18. Add a chunk that must be authenticated (SCTP_AUTH_CHUNK) | ||
2951 | * | ||
2952 | * This set option adds a chunk type that the user is requesting to be | ||
2953 | * received only in an authenticated way. Changes to the list of chunks | ||
2954 | * will only effect future associations on the socket. | ||
2955 | */ | ||
2956 | static int sctp_setsockopt_auth_chunk(struct sock *sk, | ||
2957 | char __user *optval, | ||
2958 | int optlen) | ||
2959 | { | ||
2960 | struct sctp_authchunk val; | ||
2961 | |||
2962 | if (optlen != sizeof(struct sctp_authchunk)) | ||
2963 | return -EINVAL; | ||
2964 | if (copy_from_user(&val, optval, optlen)) | ||
2965 | return -EFAULT; | ||
2966 | |||
2967 | switch (val.sauth_chunk) { | ||
2968 | case SCTP_CID_INIT: | ||
2969 | case SCTP_CID_INIT_ACK: | ||
2970 | case SCTP_CID_SHUTDOWN_COMPLETE: | ||
2971 | case SCTP_CID_AUTH: | ||
2972 | return -EINVAL; | ||
2973 | } | ||
2974 | |||
2975 | /* add this chunk id to the endpoint */ | ||
2976 | return sctp_auth_ep_add_chunkid(sctp_sk(sk)->ep, val.sauth_chunk); | ||
2977 | } | ||
2978 | |||
2979 | /* | ||
2980 | * 7.1.19. Get or set the list of supported HMAC Identifiers (SCTP_HMAC_IDENT) | ||
2981 | * | ||
2982 | * This option gets or sets the list of HMAC algorithms that the local | ||
2983 | * endpoint requires the peer to use. | ||
2984 | */ | ||
2985 | static int sctp_setsockopt_hmac_ident(struct sock *sk, | ||
2986 | char __user *optval, | ||
2987 | int optlen) | ||
2988 | { | ||
2989 | struct sctp_hmacalgo *hmacs; | ||
2990 | int err; | ||
2991 | |||
2992 | if (optlen < sizeof(struct sctp_hmacalgo)) | ||
2993 | return -EINVAL; | ||
2994 | |||
2995 | hmacs = kmalloc(optlen, GFP_KERNEL); | ||
2996 | if (!hmacs) | ||
2997 | return -ENOMEM; | ||
2998 | |||
2999 | if (copy_from_user(hmacs, optval, optlen)) { | ||
3000 | err = -EFAULT; | ||
3001 | goto out; | ||
3002 | } | ||
3003 | |||
3004 | if (hmacs->shmac_num_idents == 0 || | ||
3005 | hmacs->shmac_num_idents > SCTP_AUTH_NUM_HMACS) { | ||
3006 | err = -EINVAL; | ||
3007 | goto out; | ||
3008 | } | ||
3009 | |||
3010 | err = sctp_auth_ep_set_hmacs(sctp_sk(sk)->ep, hmacs); | ||
3011 | out: | ||
3012 | kfree(hmacs); | ||
3013 | return err; | ||
3014 | } | ||
3015 | |||
3016 | /* | ||
3017 | * 7.1.20. Set a shared key (SCTP_AUTH_KEY) | ||
3018 | * | ||
3019 | * This option will set a shared secret key which is used to build an | ||
3020 | * association shared key. | ||
3021 | */ | ||
3022 | static int sctp_setsockopt_auth_key(struct sock *sk, | ||
3023 | char __user *optval, | ||
3024 | int optlen) | ||
3025 | { | ||
3026 | struct sctp_authkey *authkey; | ||
3027 | struct sctp_association *asoc; | ||
3028 | int ret; | ||
3029 | |||
3030 | if (optlen <= sizeof(struct sctp_authkey)) | ||
3031 | return -EINVAL; | ||
3032 | |||
3033 | authkey = kmalloc(optlen, GFP_KERNEL); | ||
3034 | if (!authkey) | ||
3035 | return -ENOMEM; | ||
3036 | |||
3037 | if (copy_from_user(authkey, optval, optlen)) { | ||
3038 | ret = -EFAULT; | ||
3039 | goto out; | ||
3040 | } | ||
3041 | |||
3042 | asoc = sctp_id2assoc(sk, authkey->sca_assoc_id); | ||
3043 | if (!asoc && authkey->sca_assoc_id && sctp_style(sk, UDP)) { | ||
3044 | ret = -EINVAL; | ||
3045 | goto out; | ||
3046 | } | ||
3047 | |||
3048 | ret = sctp_auth_set_key(sctp_sk(sk)->ep, asoc, authkey); | ||
3049 | out: | ||
3050 | kfree(authkey); | ||
3051 | return ret; | ||
3052 | } | ||
3053 | |||
3054 | /* | ||
3055 | * 7.1.21. Get or set the active shared key (SCTP_AUTH_ACTIVE_KEY) | ||
3056 | * | ||
3057 | * This option will get or set the active shared key to be used to build | ||
3058 | * the association shared key. | ||
3059 | */ | ||
3060 | static int sctp_setsockopt_active_key(struct sock *sk, | ||
3061 | char __user *optval, | ||
3062 | int optlen) | ||
3063 | { | ||
3064 | struct sctp_authkeyid val; | ||
3065 | struct sctp_association *asoc; | ||
3066 | |||
3067 | if (optlen != sizeof(struct sctp_authkeyid)) | ||
3068 | return -EINVAL; | ||
3069 | if (copy_from_user(&val, optval, optlen)) | ||
3070 | return -EFAULT; | ||
3071 | |||
3072 | asoc = sctp_id2assoc(sk, val.scact_assoc_id); | ||
3073 | if (!asoc && val.scact_assoc_id && sctp_style(sk, UDP)) | ||
3074 | return -EINVAL; | ||
3075 | |||
3076 | return sctp_auth_set_active_key(sctp_sk(sk)->ep, asoc, | ||
3077 | val.scact_keynumber); | ||
3078 | } | ||
3079 | |||
3080 | /* | ||
3081 | * 7.1.22. Delete a shared key (SCTP_AUTH_DELETE_KEY) | ||
3082 | * | ||
3083 | * This set option will delete a shared secret key from use. | ||
3084 | */ | ||
3085 | static int sctp_setsockopt_del_key(struct sock *sk, | ||
3086 | char __user *optval, | ||
3087 | int optlen) | ||
3088 | { | ||
3089 | struct sctp_authkeyid val; | ||
3090 | struct sctp_association *asoc; | ||
3091 | |||
3092 | if (optlen != sizeof(struct sctp_authkeyid)) | ||
3093 | return -EINVAL; | ||
3094 | if (copy_from_user(&val, optval, optlen)) | ||
3095 | return -EFAULT; | ||
3096 | |||
3097 | asoc = sctp_id2assoc(sk, val.scact_assoc_id); | ||
3098 | if (!asoc && val.scact_assoc_id && sctp_style(sk, UDP)) | ||
3099 | return -EINVAL; | ||
3100 | |||
3101 | return sctp_auth_del_key_id(sctp_sk(sk)->ep, asoc, | ||
3102 | val.scact_keynumber); | ||
3103 | |||
3104 | } | ||
3105 | |||
3106 | |||
2949 | /* API 6.2 setsockopt(), getsockopt() | 3107 | /* API 6.2 setsockopt(), getsockopt() |
2950 | * | 3108 | * |
2951 | * Applications use setsockopt() and getsockopt() to set or retrieve | 3109 | * Applications use setsockopt() and getsockopt() to set or retrieve |
@@ -3069,6 +3227,21 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname, | |||
3069 | case SCTP_MAX_BURST: | 3227 | case SCTP_MAX_BURST: |
3070 | retval = sctp_setsockopt_maxburst(sk, optval, optlen); | 3228 | retval = sctp_setsockopt_maxburst(sk, optval, optlen); |
3071 | break; | 3229 | break; |
3230 | case SCTP_AUTH_CHUNK: | ||
3231 | retval = sctp_setsockopt_auth_chunk(sk, optval, optlen); | ||
3232 | break; | ||
3233 | case SCTP_HMAC_IDENT: | ||
3234 | retval = sctp_setsockopt_hmac_ident(sk, optval, optlen); | ||
3235 | break; | ||
3236 | case SCTP_AUTH_KEY: | ||
3237 | retval = sctp_setsockopt_auth_key(sk, optval, optlen); | ||
3238 | break; | ||
3239 | case SCTP_AUTH_ACTIVE_KEY: | ||
3240 | retval = sctp_setsockopt_active_key(sk, optval, optlen); | ||
3241 | break; | ||
3242 | case SCTP_AUTH_DELETE_KEY: | ||
3243 | retval = sctp_setsockopt_del_key(sk, optval, optlen); | ||
3244 | break; | ||
3072 | default: | 3245 | default: |
3073 | retval = -ENOPROTOOPT; | 3246 | retval = -ENOPROTOOPT; |
3074 | break; | 3247 | break; |
@@ -4840,6 +5013,118 @@ static int sctp_getsockopt_maxburst(struct sock *sk, int len, | |||
4840 | return -ENOTSUPP; | 5013 | return -ENOTSUPP; |
4841 | } | 5014 | } |
4842 | 5015 | ||
5016 | static int sctp_getsockopt_hmac_ident(struct sock *sk, int len, | ||
5017 | char __user *optval, int __user *optlen) | ||
5018 | { | ||
5019 | struct sctp_hmac_algo_param *hmacs; | ||
5020 | __u16 param_len; | ||
5021 | |||
5022 | hmacs = sctp_sk(sk)->ep->auth_hmacs_list; | ||
5023 | param_len = ntohs(hmacs->param_hdr.length); | ||
5024 | |||
5025 | if (len < param_len) | ||
5026 | return -EINVAL; | ||
5027 | if (put_user(len, optlen)) | ||
5028 | return -EFAULT; | ||
5029 | if (copy_to_user(optval, hmacs->hmac_ids, len)) | ||
5030 | return -EFAULT; | ||
5031 | |||
5032 | return 0; | ||
5033 | } | ||
5034 | |||
5035 | static int sctp_getsockopt_active_key(struct sock *sk, int len, | ||
5036 | char __user *optval, int __user *optlen) | ||
5037 | { | ||
5038 | struct sctp_authkeyid val; | ||
5039 | struct sctp_association *asoc; | ||
5040 | |||
5041 | if (len < sizeof(struct sctp_authkeyid)) | ||
5042 | return -EINVAL; | ||
5043 | if (copy_from_user(&val, optval, sizeof(struct sctp_authkeyid))) | ||
5044 | return -EFAULT; | ||
5045 | |||
5046 | asoc = sctp_id2assoc(sk, val.scact_assoc_id); | ||
5047 | if (!asoc && val.scact_assoc_id && sctp_style(sk, UDP)) | ||
5048 | return -EINVAL; | ||
5049 | |||
5050 | if (asoc) | ||
5051 | val.scact_keynumber = asoc->active_key_id; | ||
5052 | else | ||
5053 | val.scact_keynumber = sctp_sk(sk)->ep->active_key_id; | ||
5054 | |||
5055 | return 0; | ||
5056 | } | ||
5057 | |||
5058 | static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len, | ||
5059 | char __user *optval, int __user *optlen) | ||
5060 | { | ||
5061 | struct sctp_authchunks val; | ||
5062 | struct sctp_association *asoc; | ||
5063 | struct sctp_chunks_param *ch; | ||
5064 | char __user *to; | ||
5065 | |||
5066 | if (len <= sizeof(struct sctp_authchunks)) | ||
5067 | return -EINVAL; | ||
5068 | |||
5069 | if (copy_from_user(&val, optval, sizeof(struct sctp_authchunks))) | ||
5070 | return -EFAULT; | ||
5071 | |||
5072 | to = val.gauth_chunks; | ||
5073 | asoc = sctp_id2assoc(sk, val.gauth_assoc_id); | ||
5074 | if (!asoc) | ||
5075 | return -EINVAL; | ||
5076 | |||
5077 | ch = asoc->peer.peer_chunks; | ||
5078 | |||
5079 | /* See if the user provided enough room for all the data */ | ||
5080 | if (len < ntohs(ch->param_hdr.length)) | ||
5081 | return -EINVAL; | ||
5082 | |||
5083 | len = ntohs(ch->param_hdr.length); | ||
5084 | if (put_user(len, optlen)) | ||
5085 | return -EFAULT; | ||
5086 | if (copy_to_user(to, ch->chunks, len)) | ||
5087 | return -EFAULT; | ||
5088 | |||
5089 | return 0; | ||
5090 | } | ||
5091 | |||
5092 | static int sctp_getsockopt_local_auth_chunks(struct sock *sk, int len, | ||
5093 | char __user *optval, int __user *optlen) | ||
5094 | { | ||
5095 | struct sctp_authchunks val; | ||
5096 | struct sctp_association *asoc; | ||
5097 | struct sctp_chunks_param *ch; | ||
5098 | char __user *to; | ||
5099 | |||
5100 | if (len <= sizeof(struct sctp_authchunks)) | ||
5101 | return -EINVAL; | ||
5102 | |||
5103 | if (copy_from_user(&val, optval, sizeof(struct sctp_authchunks))) | ||
5104 | return -EFAULT; | ||
5105 | |||
5106 | to = val.gauth_chunks; | ||
5107 | asoc = sctp_id2assoc(sk, val.gauth_assoc_id); | ||
5108 | if (!asoc && val.gauth_assoc_id && sctp_style(sk, UDP)) | ||
5109 | return -EINVAL; | ||
5110 | |||
5111 | if (asoc) | ||
5112 | ch = (struct sctp_chunks_param*)asoc->c.auth_chunks; | ||
5113 | else | ||
5114 | ch = sctp_sk(sk)->ep->auth_chunk_list; | ||
5115 | |||
5116 | if (len < ntohs(ch->param_hdr.length)) | ||
5117 | return -EINVAL; | ||
5118 | |||
5119 | len = ntohs(ch->param_hdr.length); | ||
5120 | if (put_user(len, optlen)) | ||
5121 | return -EFAULT; | ||
5122 | if (copy_to_user(to, ch->chunks, len)) | ||
5123 | return -EFAULT; | ||
5124 | |||
5125 | return 0; | ||
5126 | } | ||
5127 | |||
4843 | SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, | 5128 | SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, |
4844 | char __user *optval, int __user *optlen) | 5129 | char __user *optval, int __user *optlen) |
4845 | { | 5130 | { |
@@ -4963,6 +5248,25 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, | |||
4963 | case SCTP_MAX_BURST: | 5248 | case SCTP_MAX_BURST: |
4964 | retval = sctp_getsockopt_maxburst(sk, len, optval, optlen); | 5249 | retval = sctp_getsockopt_maxburst(sk, len, optval, optlen); |
4965 | break; | 5250 | break; |
5251 | case SCTP_AUTH_KEY: | ||
5252 | case SCTP_AUTH_CHUNK: | ||
5253 | case SCTP_AUTH_DELETE_KEY: | ||
5254 | retval = -EOPNOTSUPP; | ||
5255 | break; | ||
5256 | case SCTP_HMAC_IDENT: | ||
5257 | retval = sctp_getsockopt_hmac_ident(sk, len, optval, optlen); | ||
5258 | break; | ||
5259 | case SCTP_AUTH_ACTIVE_KEY: | ||
5260 | retval = sctp_getsockopt_active_key(sk, len, optval, optlen); | ||
5261 | break; | ||
5262 | case SCTP_PEER_AUTH_CHUNKS: | ||
5263 | retval = sctp_getsockopt_peer_auth_chunks(sk, len, optval, | ||
5264 | optlen); | ||
5265 | break; | ||
5266 | case SCTP_LOCAL_AUTH_CHUNKS: | ||
5267 | retval = sctp_getsockopt_local_auth_chunks(sk, len, optval, | ||
5268 | optlen); | ||
5269 | break; | ||
4966 | default: | 5270 | default: |
4967 | retval = -ENOPROTOOPT; | 5271 | retval = -ENOPROTOOPT; |
4968 | break; | 5272 | break; |
diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c index 5dc094b9732d..2c17c7efad46 100644 --- a/net/sctp/ulpevent.c +++ b/net/sctp/ulpevent.c | |||
@@ -813,6 +813,43 @@ fail: | |||
813 | return NULL; | 813 | return NULL; |
814 | } | 814 | } |
815 | 815 | ||
816 | struct sctp_ulpevent *sctp_ulpevent_make_authkey( | ||
817 | const struct sctp_association *asoc, __u16 key_id, | ||
818 | __u32 indication, gfp_t gfp) | ||
819 | { | ||
820 | struct sctp_ulpevent *event; | ||
821 | struct sctp_authkey_event *ak; | ||
822 | struct sk_buff *skb; | ||
823 | |||
824 | event = sctp_ulpevent_new(sizeof(struct sctp_authkey_event), | ||
825 | MSG_NOTIFICATION, gfp); | ||
826 | if (!event) | ||
827 | goto fail; | ||
828 | |||
829 | skb = sctp_event2skb(event); | ||
830 | ak = (struct sctp_authkey_event *) | ||
831 | skb_put(skb, sizeof(struct sctp_authkey_event)); | ||
832 | |||
833 | ak->auth_type = SCTP_AUTHENTICATION_EVENT; | ||
834 | ak->auth_flags = 0; | ||
835 | ak->auth_length = sizeof(struct sctp_authkey_event); | ||
836 | |||
837 | ak->auth_keynumber = key_id; | ||
838 | ak->auth_altkeynumber = 0; | ||
839 | ak->auth_indication = indication; | ||
840 | |||
841 | /* | ||
842 | * The association id field, holds the identifier for the association. | ||
843 | */ | ||
844 | sctp_ulpevent_set_owner(event, asoc); | ||
845 | ak->auth_assoc_id = sctp_assoc2id(asoc); | ||
846 | |||
847 | return event; | ||
848 | fail: | ||
849 | return NULL; | ||
850 | } | ||
851 | |||
852 | |||
816 | /* Return the notification type, assuming this is a notification | 853 | /* Return the notification type, assuming this is a notification |
817 | * event. | 854 | * event. |
818 | */ | 855 | */ |