]> andersk Git - moira.git/blob - server/mr_scall.c
Implement MR_PROXY, to allow principals on the correctl acl to
[moira.git] / server / mr_scall.c
1 /* $Id$
2  *
3  * Do RPC
4  *
5  * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology
6  * For copying and distribution information, please see the file
7  * <mit-copyright.h>.
8  *
9  */
10
11 #include <mit-copyright.h>
12 #include "mr_server.h"
13 #include "query.h"
14
15 #include <sys/stat.h>
16 #include <sys/types.h>
17
18 #include <arpa/inet.h>
19 #include <netinet/in.h>
20
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26
27 RCSID("$Header$");
28
29 extern int nclients;
30 extern client **clients;
31 extern char *whoami;
32
33 extern int dbms_errno, mr_errcode;
34
35 void do_call(client *cl);
36 void free_rtn_tuples(client *cp);
37 int retr_callback(int argc, char **argv, void *p_cl);
38 int list_users(client *cl);
39 void do_retr(client *cl);
40 void do_access(client *cl);
41 void get_motd(client *cl);
42
43 char *procnames[] = {
44   "noop",
45   "auth",
46   "shutdown",
47   "query",
48   "access",
49   "dcm",
50   "motd",
51   "proxy",
52 };
53
54 int newqueries;
55
56 void client_read(client *cl)
57 {
58   int status, pn;
59
60   status = mr_cont_receive(cl->con, &cl->req);
61   if (status == -1)
62     return;
63   else if (status != MR_SUCCESS)
64     {
65       cl->state = CL_CLOSING;
66       if (status != MR_NOT_CONNECTED)
67         com_err(whoami, status, "while reading from socket");
68       return;
69     }
70
71   pn = cl->req.u.mr_procno;
72   if (pn < 0 || pn > MR_MAX_PROC)
73     {
74       com_err(whoami, 0, "procno out of range");
75       client_reply(cl, MR_UNKNOWN_PROC);
76       mr_destroy_reply(cl->req);
77       return;
78     }
79   log_args(procnames[pn], 2, cl->req.mr_argc, cl->req.mr_argv);
80
81   if (dormant == ASLEEP && pn != MR_NOOP && pn != MR_MOTD)
82     {
83       client_reply(cl, MR_DOWN);
84       com_err(whoami, MR_DOWN, "(query refused)");
85       mr_destroy_reply(cl->req);
86       return;
87     }
88
89   /* make sure this gets cleared before every operation */
90   dbms_errno = 0;
91
92   switch (pn)
93     {
94     case MR_NOOP:
95       client_reply(cl, MR_SUCCESS);
96       break;
97
98     case MR_AUTH:
99       do_auth(cl);
100       break;
101
102     case MR_QUERY:
103       do_retr(cl);
104       break;
105
106     case MR_ACCESS:
107       do_access(cl);
108       break;
109
110     case MR_SHUTDOWN:
111       do_shutdown(cl);
112       break;
113
114     case MR_DO_UPDATE:
115       client_reply(cl, MR_PERM);
116       break;
117
118     case MR_MOTD:
119       get_motd(cl);
120       break;
121
122     case MR_PROXY:
123       do_proxy(cl);
124       break;
125     }
126   mr_destroy_reply(cl->req);
127   memset(&cl->req, 0, sizeof(mr_params));
128 }
129
130 /* Set the final return status for a query. We always keep one more
131    free slot in cl->tuples[] than we're using so that this can't fail */
132 void client_reply(client *cl, long status)
133 {
134   cl->tuples[cl->ntuples].u.mr_status = status;
135   cl->tuples[cl->ntuples].mr_argc = 0;
136   cl->tuples[cl->ntuples].mr_argl = NULL;
137   cl->tuples[cl->ntuples].mr_argv = NULL;
138   cl->ntuples++;
139 }
140
141 void client_return_tuple(client *cl, int argc, char **argv)
142 {
143   if (cl->state == CL_CLOSING || dbms_errno)
144     return;
145
146   if (cl->ntuples == cl->tuplessize - 1)
147     {
148       int newsize = (cl->tuplessize + 4) * 2;
149       mr_params *newtuples;
150
151       newtuples = realloc(cl->tuples, newsize * sizeof(mr_params));
152       if (!newtuples)
153         {
154           free_rtn_tuples(cl);
155           dbms_errno = mr_errcode = MR_NO_MEM;
156           return;
157         }
158       cl->tuplessize = newsize;
159       cl->tuples = newtuples;
160     }
161
162   cl->tuples[cl->ntuples].u.mr_status = MR_MORE_DATA;
163   cl->tuples[cl->ntuples].mr_argc = argc;
164   cl->tuples[cl->ntuples].mr_argl = NULL;
165   cl->tuples[cl->ntuples].mr_argv = mr_copy_args(argv, argc);
166   cl->ntuples++;
167 }
168
169 void client_write(client *cl)
170 {
171   int status;
172
173   status = mr_send(cl->con, &cl->tuples[cl->nexttuple]);
174   if (status)
175     {
176       com_err(whoami, status, "writing to socket");
177       cl->state = CL_CLOSING;
178     }
179   else
180     {
181       cl->nexttuple++;
182       if (cl->nexttuple == cl->ntuples)
183         free_rtn_tuples(cl);
184     }
185 }
186
187 void free_rtn_tuples(client *cl)
188 {
189   for (cl->ntuples--; cl->ntuples >= 0; cl->ntuples--)
190     free_argv(cl->tuples[cl->ntuples].mr_argv,
191               cl->tuples[cl->ntuples].mr_argc);
192   free(cl->tuples);
193
194   cl->tuples = xmalloc(sizeof(mr_params));
195   cl->tuplessize = 1;
196   cl->ntuples = cl->nexttuple = 0;
197 }
198
199 void do_retr(client *cl)
200 {
201   char *queryname;
202   int status;
203
204   if (cl->req.mr_argc < 1)
205     {
206       client_reply(cl, MR_ARGS);
207       com_err(whoami, MR_ARGS, "got nameless query");
208       return;
209     }
210   queryname = cl->req.mr_argv[0];
211   newqueries++;
212
213   if (!strcmp(queryname, "_list_users"))
214     status = list_users(cl);
215   else
216     status = mr_process_query(cl, queryname, cl->req.mr_argc - 1,
217                               cl->req.mr_argv + 1, retr_callback, cl);
218
219   client_reply(cl, status);
220
221   com_err(whoami, 0, "Query complete.");
222 }
223
224 int retr_callback(int argc, char **argv, void *p_cl)
225 {
226   client *cl = p_cl;
227
228   mr_trim_args(argc, argv);
229   client_return_tuple(cl, argc, argv);
230 }
231
232 void do_access(client *cl)
233 {
234   int status;
235
236   if (cl->req.mr_argc < 1)
237     {
238       client_reply(cl, MR_ARGS);
239       com_err(whoami, MR_ARGS, "got nameless access");
240       return;
241     }
242
243   status = mr_check_access(cl, cl->req.mr_argv[0], cl->req.mr_argc - 1,
244                            cl->req.mr_argv + 1);
245   client_reply(cl, status);
246
247   com_err(whoami, 0, "Access check complete.");
248 }
249
250 void get_motd(client *cl)
251 {
252   int motd;
253   char *buffer;
254   struct stat statb;
255
256   if (stat(MOIRA_MOTD_FILE, &statb) == -1)
257     {
258       client_reply(cl, MR_SUCCESS);
259       return;
260     }
261   
262   buffer = malloc(statb.st_size + 1);
263   if (!buffer)
264     {
265       client_reply(cl, MR_NO_MEM);
266       return;
267     }
268
269   motd = open(MOIRA_MOTD_FILE, 0, O_RDONLY);
270   if (motd)
271     {
272       read(motd, buffer, statb.st_size);
273       close(motd);
274       buffer[statb.st_size] = '\0';
275       client_return_tuple(cl, 1, &buffer);
276       client_reply(cl, MR_SUCCESS);
277     }
278   else
279     client_reply(cl, errno);
280
281   free(buffer);
282 }
283
284 int list_users(client *cl)
285 {
286   char *argv[5];
287   char buf[30];
288   char buf1[30];
289   int i;
290   char *cp;
291
292   for (i = 0; i < nclients; i++)
293     {
294       client *c = clients[i];
295       argv[0] = c->clname;
296       argv[1] = inet_ntoa(c->haddr.sin_addr);
297       argv[2] = buf;
298       sprintf(buf, "port %d", ntohs(c->haddr.sin_port));
299       argv[3] = ctime(&c->last_time_used);
300       cp = strchr(argv[3], '\n');
301       if (cp)
302         *cp = '\0';
303       argv[4] = buf1;
304       sprintf(buf1, "[#%d]", c->id);
305       client_return_tuple(cl, 5, argv);
306     }
307   return MR_SUCCESS;
308 }
309
This page took 0.053354 seconds and 5 git commands to generate.