Merge pull request #15 from pobept/dictionary-redback
[freeradius.git] / src / modules / rlm_replicate / rlm_replicate.c
1 /*
2  * rlm_replicate.c
3  *
4  * Version:     $Id$
5  *
6  *   This program is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation; either version 2 of the License, or
9  *   (at your option) any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program; if not, write to the Free Software
18  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2000,2006  The FreeRADIUS server project
21  * Copyright 2000  your name <your address>
22  */
23
24 #include <freeradius-devel/ident.h>
25 RCSID("$Id$")
26
27 #include <freeradius-devel/radiusd.h>
28 #include <freeradius-devel/modules.h>
29
30 #ifdef WITH_PROXY
31 static void cleanup(RADIUS_PACKET *packet)
32 {
33         if (!packet) return;
34         if (packet->sockfd >= 0) close(packet->sockfd);
35         rad_free(&packet);
36 }
37
38 /*
39  *      Write accounting information to this modules database.
40  */
41 static int replicate_packet(void *instance, REQUEST *request)
42 {
43         int rcode = RLM_MODULE_NOOP;
44         VALUE_PAIR *vp, *last;
45         home_server *home;
46         REALM *realm;
47         home_pool_t *pool;
48         RADIUS_PACKET *packet = NULL;
49
50         instance = instance;    /* -Wunused */
51         last = request->config_items;
52
53         /*
54          *      Send as many packets as necessary to different
55          *      destinations.
56          */
57         while (1) {
58                 vp = pairfind(last, PW_REPLICATE_TO_REALM, 0);
59                 if (!vp) break;
60
61                 last = vp->next;
62
63                 realm = realm_find2(vp->vp_strvalue);
64                 if (!realm) {
65                         RDEBUG2("ERROR: Cannot Replicate to unknown realm %s", realm);
66                         continue;
67                 }
68                 
69                 /*
70                  *      We shouldn't really do this on every loop.
71                  */
72                 switch (request->packet->code) {
73                 default:
74                         RDEBUG2("ERROR: Cannot replicate unknown packet code %d",
75                                 request->packet->code);
76                         cleanup(packet);
77                         return RLM_MODULE_FAIL;
78                 
79                 case PW_AUTHENTICATION_REQUEST:
80                         pool = realm->auth_pool;
81                         break;
82                         
83 #ifdef WITH_ACCOUNTING
84                         
85                 case PW_ACCOUNTING_REQUEST:
86                         pool = realm->acct_pool;
87                         break;
88 #endif
89                         
90 #ifdef WITH_COA
91                 case PW_COA_REQUEST:
92                 case PW_DISCONNECT_REQUEST:
93                         pool = realm->acct_pool;
94                         break;
95 #endif
96                 }
97                 
98                 if (!pool) {
99                         RDEBUG2(" WARNING: Cancelling replication to Realm %s, as the realm is local.", realm->name);
100                         continue;
101                 }
102                 
103                 home = home_server_ldb(realm->name, pool, request);
104                 if (!home) {
105                         RDEBUG2("ERROR: Failed to find live home server for realm %s",
106                                 realm->name);
107                         continue;
108                 }
109                 
110                 if (!packet) {
111                         packet = rad_alloc(1);
112                         if (!packet) return RLM_MODULE_FAIL;
113                         packet->sockfd = -1;
114                         packet->code = request->packet->code;
115                         packet->id = fr_rand() & 0xff;
116
117                         packet->sockfd = fr_socket(&home->src_ipaddr, 0);
118                         if (packet->sockfd < 0) {
119                                 RDEBUG("ERROR: Failed opening socket: %s", fr_strerror());
120                                 cleanup(packet);
121                                 return RLM_MODULE_FAIL;
122                         }
123
124                         packet->vps = paircopy(request->packet->vps);
125                         if (!packet->vps) {
126                                 RDEBUG("ERROR: Out of memory!");
127                                 cleanup(packet);
128                                 return RLM_MODULE_FAIL;
129                         }
130
131                         /*
132                          *      For CHAP, create the CHAP-Challenge if
133                          *      it doesn't exist.
134                          */
135                         if ((request->packet->code == PW_AUTHENTICATION_REQUEST) &&
136                             (pairfind(request->packet->vps, PW_CHAP_PASSWORD, 0) != NULL) &&
137                             (pairfind(request->packet->vps, PW_CHAP_CHALLENGE, 0) == NULL)) {
138                                 vp = radius_paircreate(request, &packet->vps,
139                                                        PW_CHAP_CHALLENGE, 0,
140                                                        PW_TYPE_OCTETS);
141                                 vp->length = AUTH_VECTOR_LEN;
142                                 memcpy(vp->vp_strvalue, request->packet->vector,
143                                        AUTH_VECTOR_LEN);
144                         }
145                 } else {
146                         size_t i;
147
148                         for (i = 0; i < sizeof(packet->vector); i++) {
149                                 packet->vector[i] = fr_rand() & 0xff;
150                         }
151
152                         packet->id++;
153                         free(packet->data);
154                         packet->data = NULL;
155                         packet->data_len = 0;
156                 }
157
158                 /*
159                  *      (Re)-Write these.
160                  */
161                 packet->dst_ipaddr = home->ipaddr;
162                 packet->dst_port = home->port;
163                 memset(&packet->src_ipaddr, 0, sizeof(packet->src_ipaddr));
164                 packet->src_port = 0;
165                 
166                 /*
167                  *      Encode, sign and then send the packet.
168                  */
169                 RDEBUG("Replicating packet to Realm %s", realm->name);
170                 if (rad_send(packet, NULL, home->secret) < 0) {
171                         RDEBUG("ERROR: Failed replicating packet: %s",
172                                fr_strerror());
173                         cleanup(packet);
174                         return RLM_MODULE_FAIL;
175                 }
176
177                 /*
178                  *      We've sent it to at least one destination.
179                  */
180                 rcode = RLM_MODULE_OK;
181         }
182
183         cleanup(packet);
184         return rcode;
185 }
186 #else
187 static int replicate_packet(void *instance, REQUEST *request)
188 {
189         RDEBUG("Replication is unsupported in this build.");
190         return RLM_MODULE_FAIL;
191 }
192 #endif
193
194 /*
195  *      The module name should be the only globally exported symbol.
196  *      That is, everything else should be 'static'.
197  *
198  *      If the module needs to temporarily modify it's instantiation
199  *      data, the type should be changed to RLM_TYPE_THREAD_UNSAFE.
200  *      The server will then take care of ensuring that the module
201  *      is single-threaded.
202  */
203 module_t rlm_replicate = {
204         RLM_MODULE_INIT,
205         "replicate",
206         RLM_TYPE_THREAD_SAFE,           /* type */
207         NULL,                           /* instantiation */
208         NULL,                           /* detach */
209         {
210                 NULL,                   /* authentication */
211                 replicate_packet,       /* authorization */
212                 NULL,                   /* preaccounting */
213                 replicate_packet,       /* accounting */
214                 NULL,                   /* checksimul */
215                 NULL,                   /* pre-proxy */
216                 NULL,                   /* post-proxy */
217                 NULL                    /* post-auth */
218 #ifdef WITH_COA
219                 , replicate_packet,
220                 NULL
221 #endif
222         },
223 };