Initial revision
[become] / src / check.c
CommitLineData
c4f2d992 1/* -*-c-*-
2 *
3 * $Id: check.c,v 1.1 1997/07/21 13:47:53 mdw Exp $
4 *
5 * Check validity of requests
6 *
7 * (c) 1997 EBI
8 */
9
10/*----- Licencing notice --------------------------------------------------*
11 *
12 * This file is part of `become'
13 *
14 * `Become' is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * `Become' is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with `become'; if not, write to the Free Software
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 */
28
29/*----- Revision history --------------------------------------------------*
30 *
31 * $Log: check.c,v $
32 * Revision 1.1 1997/07/21 13:47:53 mdw
33 * Initial revision
34 *
35 */
36
37/*----- Header files ------------------------------------------------------*/
38
39/* --- ANSI headers --- */
40
41#include <ctype.h>
42#include <errno.h>
43#include <stdio.h>
44#include <stdlib.h>
45#include <string.h>
46#include <time.h>
47
48/* --- Unix headers --- */
49
50#include <sys/time.h>
51#include <sys/types.h>
52#include <sys/socket.h>
53
54#include <netinet/in.h>
55
56#include <arpa/inet.h>
57
58#include <netdb.h>
59#include <unistd.h>
60
61/* --- Local headers --- */
62
63#include "become.h"
64#include "config.h"
65#include "crypt.h"
66#include "idea.h"
67#include "lexer.h"
68#include "name.h"
69#include "rule.h"
70#include "parser.h"
71#include "tx.h"
72#include "utils.h"
73
74/*----- Main code ---------------------------------------------------------*/
75
76/* --- @check__client@ --- *
77 *
78 * Arguments: @request *rq@ = pointer to request buffer
79 * @const char *serv@ = pointer to the server
80 * @int port@ = port number to use
81 *
82 * Returns: Nonzero if OK, zero if forbidden
83 *
84 * Use: Contacts a server to decide whether the request is OK.
85 */
86
87static int check__client(request *rq, const char *serv, int port)
88{
89 int fd;
90 struct sockaddr_in ssin;
91 unsigned char crq[crq_size];
92 unsigned char k[IDEA_KEYSIZE];
93 unsigned char sk[IDEA_KEYSIZE];
94 time_t t;
95 pid_t pid;
96
97 /* --- Create my socket --- */
98
99 if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
100 die("couldn't create socket: %s", strerror(errno));
101
102 /* --- Bind myself to some address --- */
103
104 {
105 struct sockaddr_in sin;
106
107 sin.sin_family = AF_INET;
108 sin.sin_port = 0;
109 sin.sin_addr.s_addr = htonl(INADDR_ANY);
110
111 if (bind(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0)
112 die("couldn't bind socket to address: %s", strerror(errno));
113 }
114
115 /* --- Find the server's address --- */
116
117 {
118 struct hostent *he;
119
120 /* --- Resolve the server's name --- */
121
122 if ((he = gethostbyname(serv)) == 0)
123 die("couldn't find server host `%s'", serv);
124
125 /* --- Build the address block --- */
126
127 ssin.sin_family = AF_INET;
128 ssin.sin_port = htons(port);
129 memcpy(&ssin.sin_addr, he->h_addr, sizeof(struct in_addr));
130 }
131
132 /* --- Read in the encryption key --- */
133
134 {
135 FILE *fp;
136
137 if ((fp = fopen(file_KEY, "r")) == 0) {
138 die("couldn't open key file `%s': %s", file_KEY,
139 strerror(errno));
140 }
141 tx_getBits(k, 128, fp);
142 }
143
144 /* --- Now build a request packet --- */
145
146 t = time(0);
147 pid = getpid();
148 crypt_packRequest(rq, crq, t, pid, k, sk);
149
150 /* --- Send the packet to the server --- */
151
152 if (sendto(fd, (char *)crq, sizeof(crq), 0,
153 (struct sockaddr *)&ssin, sizeof(ssin)) < 0) {
154 burn(k);
155 die("couldn't send request to server: %s", strerror(errno));
156 }
157 burn(k);
158
159 /* --- Now wait for a reply --- */
160
161 {
162 fd_set fds;
163 struct timeval when, now, tv;
164
165 gettimeofday(&when, 0);
166 when.tv_sec += 10;
167
168 for (;;) {
169 int i;
170
171 /* --- Sort out when to return --- */
172
173 gettimeofday(&now, 0);
174 if (now.tv_usec > when.tv_usec) {
175 now.tv_usec -= 1000000;
176 now.tv_sec += 1;
177 }
178 tv.tv_sec = when.tv_sec - now.tv_sec;
179 tv.tv_usec = when.tv_usec - now.tv_usec;
180
181 /* --- Sort out file descriptors to watch --- */
182
183 FD_ZERO(&fds);
184 FD_SET(fd, &fds);
185
186 /* --- Wait for them --- */
187
188 i = select(FD_SETSIZE, &fds, 0, 0, &tv);
189 if (i == 0)
190 die("no answer from server");
191 if (i < 0)
192 die("error waiting for reply: %s", strerror(errno));
193
194 /* --- A reply should be waiting now --- */
195
196 {
197 struct sockaddr_in sin;
198 int slen = sizeof(sin);
199 unsigned char buff[256];
200 int answer;
201
202 /* --- Read the reply data --- */
203
204 if (recvfrom(fd, (char *)buff, sizeof(buff), 0,
205 (struct sockaddr *)&sin, &slen) < 0)
206 die("error reading server's reply: %s", strerror(errno));
207
208 /* --- Verify the sender --- */
209
210 if (sin.sin_addr.s_addr != ssin.sin_addr.s_addr ||
211 sin.sin_port != ssin.sin_port)
212 continue;
213
214 /* --- Unpack and verify the response --- */
215
216 answer = crypt_unpackReply(buff, sk, t, pid);
217 if (answer < 0)
218 continue;
219 return (answer);
220 }
221 }
222 }
223
224 die("internal error: can't get here in check_client");
225 return (0);
226}
227
228/* --- @check@ --- *
229 *
230 * Arguments: @request *rq@ = pointer to request buffer
231 *
232 * Returns: Nonzero if OK, zero if forbidden
233 *
234 * Use: Checks to see if the request is acceptable.
235 */
236
237int check(request *rq)
238{
239 FILE *fp;
240
241 /* --- Check if we need to talk to a server --- */
242
243 if ((fp = fopen(file_SERVER, "r")) != 0) {
244 char buff[64];
245 int port;
246 int ch;
247
248 if (fscanf(fp, " %63[^: \t] ", buff) < 1)
249 die("error in `%s'", file_SERVER);
250 ch = getc(fp);
251 if (ch == ':') {
252 char b[64];
253 struct servent *se;
254
255 fscanf(fp, "%s", b);
256 if ((se = getservbyname(b, 0)) != 0)
257 port = ntohs(se->s_port);
258 else if ((port = atoi(b)) == 0)
259 die("error in `%s'", file_SERVER);
260 } else {
261 struct servent *se;
262
263 if ((se = getservbyname(quis(), "udp")) == 0)
264 die("no idea which port to use");
265 port = ntohs(se->s_port);
266 }
267 fclose(fp);
268 return (check__client(rq, buff, port));
269 }
270
271 /* --- Read the configuration in and go --- */
272
273 if ((fp = fopen(file_RULES, "r")) == 0) {
274 die("couldn't read configuration file `%s': %s",
275 file_RULES, strerror(errno));
276 }
277
278 name_init();
279 rule_init();
280 lexer_scan(fp);
281 yyparse();
282
283 return (rule_check(rq));
284}
285
286/*----- That's all, folks -------------------------------------------------*/