source: trunk/third/moira/server/mr_scall.c @ 23740

Revision 23740, 6.8 KB checked in by broder, 16 years ago (diff)
In moira: * New CVS snapshot (Trac: #195) * Drop patches that have been incorporated upstream. * Update to build without krb4 on systems that no longer have it. This doesn't build yet on squeeze, which lacks a krb4 library, but I'm committing now before I start hacking away at a patch to fix that.
Line 
1/* $Id: mr_scall.c,v 1.39 2006-08-22 17:36:26 zacheiss Exp $
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
27RCSID("$Header: /afs/athena.mit.edu/astaff/project/moiradev/repository/moira/server/mr_scall.c,v 1.39 2006-08-22 17:36:26 zacheiss Exp $");
28
29extern int nclients;
30extern client **clients;
31extern char *whoami;
32
33extern int dbms_errno, mr_errcode;
34
35int max_version;
36
37void do_call(client *cl);
38void free_rtn_tuples(client *cp);
39int retr_callback(int argc, char **argv, void *p_cl);
40int list_users(client *cl);
41void do_retr(client *cl);
42void do_access(client *cl);
43void get_motd(client *cl);
44void do_version(client *cl);
45
46char *procnames[] = {
47  "noop",
48  "auth",
49  "shutdown",
50  "query",
51  "access",
52  "dcm",
53  "motd",
54  "proxy",
55  "version",
56  "auth_krb5",
57};
58
59int newqueries;
60
61void client_read(client *cl)
62{
63  int status, pn;
64
65  status = mr_cont_receive(cl->con, &cl->req);
66  if (status == -1)
67    return;
68  else if (status != MR_SUCCESS)
69    {
70      cl->state = CL_CLOSING;
71      if (status != MR_NOT_CONNECTED)
72        com_err(whoami, status, "while reading from socket");
73      return;
74    }
75
76  pn = cl->req.u.mr_procno;
77  if (pn < 0 || pn > MR_MAX_PROC)
78    {
79      com_err(whoami, 0, "procno out of range");
80      client_reply(cl, MR_UNKNOWN_PROC);
81      goto out;
82    }
83  log_args(procnames[pn], 2, cl->req.mr_argc, cl->req.mr_argv);
84
85  if (dormant == ASLEEP && pn != MR_NOOP && pn != MR_MOTD)
86    {
87      client_reply(cl, MR_DOWN);
88      com_err(whoami, MR_DOWN, "(query refused)");
89      goto out;
90    }
91
92  /* make sure this gets cleared before every operation */
93  dbms_errno = 0;
94
95  switch (pn)
96    {
97    case MR_NOOP:
98      client_reply(cl, MR_SUCCESS);
99      break;
100
101    case MR_AUTH:
102      do_auth(cl);
103      break;
104
105    case MR_QUERY:
106      do_retr(cl);
107      break;
108
109    case MR_ACCESS:
110      do_access(cl);
111      break;
112
113    case MR_SHUTDOWN:
114      do_shutdown(cl);
115      break;
116
117    case MR_DO_UPDATE:
118      client_reply(cl, MR_PERM);
119      break;
120
121    case MR_MOTD:
122      get_motd(cl);
123      break;
124
125    case MR_PROXY:
126      do_proxy(cl);
127      break;
128
129    case MR_SETVERSION:
130      do_version(cl);
131      break;
132
133    case MR_KRB5_AUTH:
134      do_krb5_auth(cl);
135      break;
136
137    }
138
139out:
140  mr_destroy_reply(cl->req);
141  memset(&cl->req, 0, sizeof(mr_params));
142}
143
144/* Set the final return status for a query. We always keep one more
145   free slot in cl->tuples[] than we're using so that this can't fail */
146void client_reply(client *cl, long status)
147{
148  cl->tuples[cl->ntuples].u.mr_status = status;
149  cl->tuples[cl->ntuples].mr_argc = 0;
150  cl->tuples[cl->ntuples].mr_argl = NULL;
151  cl->tuples[cl->ntuples].mr_argv = NULL;
152  cl->ntuples++;
153}
154
155void client_return_tuple(client *cl, int argc, char **argv)
156{
157  if (cl->state == CL_CLOSING || dbms_errno)
158    return;
159
160  if (cl->ntuples == cl->tuplessize - 1)
161    {
162      int newsize = (cl->tuplessize + 4) * 2;
163      mr_params *newtuples;
164
165      newtuples = realloc(cl->tuples, newsize * sizeof(mr_params));
166      if (!newtuples)
167        {
168          free_rtn_tuples(cl);
169          dbms_errno = mr_errcode = MR_NO_MEM;
170          return;
171        }
172      cl->tuplessize = newsize;
173      cl->tuples = newtuples;
174    }
175
176  cl->tuples[cl->ntuples].u.mr_status = MR_MORE_DATA;
177  cl->tuples[cl->ntuples].mr_argc = argc;
178  cl->tuples[cl->ntuples].mr_argl = NULL;
179  cl->tuples[cl->ntuples].mr_argv = mr_copy_args(argv, argc);
180  cl->ntuples++;
181}
182
183void client_write(client *cl)
184{
185  int status;
186
187  status = mr_send(cl->con, &cl->tuples[cl->nexttuple]);
188  if (status)
189    {
190      com_err(whoami, status, "writing to socket");
191      cl->state = CL_CLOSING;
192    }
193  else
194    {
195      cl->nexttuple++;
196      if (cl->nexttuple == cl->ntuples)
197        free_rtn_tuples(cl);
198    }
199}
200
201void free_rtn_tuples(client *cl)
202{
203  for (cl->ntuples--; cl->ntuples >= 0; cl->ntuples--)
204    free_argv(cl->tuples[cl->ntuples].mr_argv,
205              cl->tuples[cl->ntuples].mr_argc);
206  free(cl->tuples);
207
208  cl->tuples = xmalloc(sizeof(mr_params));
209  cl->tuplessize = 1;
210  cl->ntuples = cl->nexttuple = 0;
211}
212
213void do_retr(client *cl)
214{
215  char *queryname;
216  int status;
217
218  if (cl->req.mr_argc < 1)
219    {
220      client_reply(cl, MR_ARGS);
221      com_err(whoami, MR_ARGS, "got nameless query");
222      return;
223    }
224  queryname = cl->req.mr_argv[0];
225  newqueries++;
226
227  if (!strcmp(queryname, "_list_users"))
228    status = list_users(cl);
229  else
230    status = mr_process_query(cl, queryname, cl->req.mr_argc - 1,
231                              cl->req.mr_argv + 1, retr_callback, cl);
232
233  client_reply(cl, status);
234
235  com_err(whoami, 0, "Query complete.");
236}
237
238int retr_callback(int argc, char **argv, void *p_cl)
239{
240  client *cl = p_cl;
241
242  mr_trim_args(argc, argv);
243  client_return_tuple(cl, argc, argv);
244}
245
246void do_access(client *cl)
247{
248  int status;
249
250  if (cl->req.mr_argc < 1)
251    {
252      client_reply(cl, MR_ARGS);
253      com_err(whoami, MR_ARGS, "got nameless access");
254      return;
255    }
256
257  status = mr_check_access(cl, cl->req.mr_argv[0], cl->req.mr_argc - 1,
258                           cl->req.mr_argv + 1);
259  client_reply(cl, status);
260
261  com_err(whoami, 0, "Access check complete.");
262}
263
264void do_version(client *cl)
265{
266  if (cl->req.mr_argc != 1)
267    {
268      client_reply(cl, MR_ARGS);
269      com_err(whoami, MR_ARGS, "incorrect number of arguments");
270      return;
271    }
272
273  cl->version = atoi(cl->req.mr_argv[0]);
274  if (cl->version == -1)
275    cl->version = max_version;
276
277  client_reply(cl, cl->version == max_version ? MR_SUCCESS :
278               cl->version < max_version ? MR_VERSION_LOW : MR_VERSION_HIGH);
279}
280
281void get_motd(client *cl)
282{
283  int motd;
284  char *buffer;
285  struct stat statb;
286
287  if (stat(MOIRA_MOTD_FILE, &statb) == -1)
288    {
289      client_reply(cl, MR_SUCCESS);
290      return;
291    }
292 
293  buffer = malloc(statb.st_size + 1);
294  if (!buffer)
295    {
296      client_reply(cl, MR_NO_MEM);
297      return;
298    }
299
300  motd = open(MOIRA_MOTD_FILE, 0, O_RDONLY);
301  if (motd)
302    {
303      read(motd, buffer, statb.st_size);
304      close(motd);
305      buffer[statb.st_size] = '\0';
306      client_return_tuple(cl, 1, &buffer);
307      client_reply(cl, MR_SUCCESS);
308    }
309  else
310    client_reply(cl, errno);
311
312  free(buffer);
313}
314
315int list_users(client *cl)
316{
317  char *argv[5];
318  char buf[30];
319  char buf1[30];
320  int i;
321  char *cp;
322
323  for (i = 0; i < nclients; i++)
324    {
325      client *c = clients[i];
326      argv[0] = c->clname;
327      argv[1] = inet_ntoa(c->haddr.sin_addr);
328      argv[2] = buf;
329      sprintf(buf, "port %d", ntohs(c->haddr.sin_port));
330      argv[3] = ctime(&c->last_time_used);
331      cp = strchr(argv[3], '\n');
332      if (cp)
333        *cp = '\0';
334      argv[4] = buf1;
335      sprintf(buf1, "[#%d]", c->id);
336      client_return_tuple(cl, 5, argv);
337    }
338  return MR_SUCCESS;
339}
340
Note: See TracBrowser for help on using the repository browser.