Move F-Ticks logging to fticks.c.
[radsecproxy.git] / fticks.c
1 /* Copyright (C) 2011 NORDUnet A/S
2  * See LICENSE for information about licensing.
3  */
4
5 #include <stdio.h>              /* For sprintf().  */
6 #include <string.h>
7 #include <nettle/sha.h>
8 #include <nettle/hmac.h>
9
10 #include <regex.h>
11 #include <pthread.h>
12 #include <sys/time.h>
13 #include "list.h"
14 #include "radsecproxy.h"
15 #include "debug.h"
16
17 #include "fticks.h"
18
19 static void
20 format_hash(const uint8_t *hash, size_t out_len, uint8_t *out)
21 {
22     int i;
23
24     for (i = 0; i < out_len / 2; i++)
25         sprintf((char *) out + i*2, "%02x", hash[i % SHA256_DIGEST_SIZE]);
26 }
27
28 static void
29 hash(const uint8_t *in,
30      const uint8_t *key,
31      size_t out_len,
32      uint8_t *out)
33 {
34     if (key == NULL) {
35         struct sha256_ctx ctx;
36         uint8_t hash[SHA256_DIGEST_SIZE];
37
38         sha256_init(&ctx);
39         sha256_update(&ctx, strlen((char *) in), in);
40         sha256_digest(&ctx, sizeof(hash), hash);
41         format_hash(hash, out_len, out);
42     }
43     else {
44         struct hmac_sha256_ctx ctx;
45         uint8_t hash[SHA256_DIGEST_SIZE];
46
47         hmac_sha256_set_key(&ctx, strlen((char *) key), key);
48         hmac_sha256_update(&ctx, strlen((char *) in), in);
49         hmac_sha256_digest(&ctx, sizeof(hash), hash);
50         format_hash(hash, out_len, out);
51     }
52 }
53
54 /** Hash the MAC in \a IN, keying with \a KEY if it's not NULL.
55
56     \a IN and \a KEY are NULL terminated strings.
57
58     \a IN is sanitised by lowercasing it, removing all but [0-9a-f]
59     and truncating it at first ';' (due to RADIUS praxis with tacking
60     on SSID to MAC in Calling-Station-Id).  */
61 void
62 fticks_hashmac(const uint8_t *in,
63                const uint8_t *key,
64                size_t out_len,
65                uint8_t *out)
66 {
67     /* TODO: lowercase */
68     /* TODO: s/[!0-9a-f]//1 */
69     /* TODO: truncate after first ';', if any */
70
71     hash(in, key, out_len, out);
72 }
73
74 void
75 fticks_log(const struct options *options,
76            const struct client *client,
77            const struct radmsg *msg,
78            const struct rqout *rqout)
79 {
80     unsigned char *username = NULL;
81     unsigned char *realm = NULL;
82     uint8_t visinst[8+40+1+1]; /* Room for 40 octets of VISINST.  */
83     uint8_t *macin = NULL;
84     uint8_t macout[2*32+1]; /* Room for ASCII representation of SHA256.  */
85
86     username = radattr2ascii(radmsg_gettype(rqout->rq->msg,
87                                             RAD_Attr_User_Name));
88     if (username != NULL) {
89         realm = (unsigned char *) strrchr((char *) username, '@');
90         if (realm != NULL)
91             realm++;
92         else
93             realm = (unsigned char *) "";
94     }
95
96     memset(visinst, 0, sizeof(visinst));
97     if (options->fticks_reporting == RSP_FTICKS_REPORTING_FULL)
98         snprintf((char *) visinst, sizeof(visinst), "VISINST=%s#",
99                  client->conf->name);
100
101 #define BOGUS_MAC "00:00:00:00:00:00" /* FIXME: Is there a standard
102                                        * for bogus MAC addresses?  */
103     memset(macout, 0, sizeof(macout));
104     strncpy((char *) macout, BOGUS_MAC, sizeof(macout) - 1);
105     if (options->fticks_mac != RSP_FTICKS_MAC_STATIC) {
106         macin = radattr2ascii(radmsg_gettype(rqout->rq->msg,
107                                              RAD_Attr_Calling_Station_Id));
108     }
109 #if RS_TESTING || 1
110     if (macin == NULL)
111         macin = (uint8_t *) strdup(BOGUS_MAC);
112 #endif  /* RS_TESTING */
113
114     switch (options->fticks_mac)
115     {
116     case RSP_FTICKS_MAC_STATIC:
117         memcpy(macout, BOGUS_MAC, sizeof(BOGUS_MAC));
118         break;
119     case RSP_FTICKS_MAC_ORIGINAL:
120         memcpy(macout, macin, sizeof(macout));
121         break;
122     case RSP_FTICKS_MAC_VENDOR_HASHED:
123         fticks_hashmac(macin + 3, NULL, sizeof(macout), macout);
124         break;
125     case RSP_FTICKS_MAC_VENDOR_KEY_HASHED:
126         fticks_hashmac(macin + 3, options->fticks_key, sizeof(macout),
127                        macout);
128         break;
129     case RSP_FTICKS_MAC_FULLY_HASHED:
130         fticks_hashmac(macin, NULL, sizeof(macout), macout);
131         break;
132     case RSP_FTICKS_MAC_FULLY_KEY_HASHED:
133         fticks_hashmac(macin, options->fticks_key, sizeof(macout), macout);
134         break;
135     default:
136         debugx(2, DBG_ERR, "invalid fticks mac configuration: %d",
137                options->fticks_mac);
138     }
139     debug(0xff,
140           "F-TICKS/eduroam/1.0#REALM=%s#VISCOUNTRY=%s#%sCSI=%s#RESULT=%s#",
141           realm,
142           client->conf->fticks_viscountry,
143           visinst,
144           macout,
145           msg->code == RAD_Access_Accept ? "OK" : "FAIL");
146     if (macin != NULL)
147         free(macin);
148     if (username != NULL)
149         free(username);
150 }
151
152 /* Local Variables: */
153 /* c-file-style: "stroustrup" */
154 /* End: */