]> andersk Git - moira.git/blob - server/mr_scall.c
90e661b94d09793fda474ba42846bffa414cefe8
[moira.git] / server / mr_scall.c
1 /*
2  *      $Source$
3  *      $Author$
4  *      $Header$
5  *
6  *      Copyright (C) 1987 by the Massachusetts Institute of Technology
7  *      For copying and distribution information, please see the file
8  *      <mit-copyright.h>.
9  *
10  */
11
12 #ifndef lint
13 static char *rcsid_sms_scall_c = "$Header$";
14 #endif lint
15
16 #include <mit-copyright.h>
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <sys/file.h>
20 #include <fcntl.h>
21 #include <string.h>
22 #include <netinet/in.h>
23 #include <arpa/inet.h>
24 #include <krb.h>
25 #include <errno.h>
26 #include "mr_server.h"
27 #include "query.h"
28 extern char buf1[];
29 extern int nclients;
30 extern char *whoami;
31 extern int errno;
32
33 extern void clist_delete(), do_auth(), do_shutdown();
34 void do_call();
35 extern int dbms_errno, mr_errcode;
36 static int row_count;
37
38 /* Put this in a variable so that we can patch it if necessary */
39 int max_row_count = 4096;
40
41 /*
42  * Welcome to the (finite state) machine (highest level).
43  */
44 void do_client(client *cp)
45 {
46   struct stat stbuf;
47
48   free_rtn_tuples(cp);
49   if (OP_STATUS(cp->pending_op) == OP_CANCELLED)
50     {
51       com_err(whoami, 0,
52               "Closed connection (now %d client%s, %d new queries, %d old)",
53               nclients - 1, nclients != 2 ? "s" : "", newqueries, oldqueries);
54       clist_delete(cp);
55       /* if we no longer have any clients, and we're supposed to
56        * go down, then go down now.
57        */
58       if ((dormant == AWAKE) && (nclients == 0) &&
59           (stat(MOIRA_MOTD_FILE, &stbuf) == 0))
60         {
61           com_err(whoami, 0, "motd file exists, slumbertime");
62           dormant = SLEEPY;
63         }
64       return;
65     }
66   switch (cp->action)
67     {
68     case CL_ACCEPT:
69     case CL_SEND:
70       /* Start recieving next request */
71       initialize_operation(cp->pending_op, mr_start_recv,
72                            (char *)&cp->args, NULL);
73       queue_operation(cp->con, CON_INPUT, cp->pending_op);
74       cp->action = CL_RECEIVE;
75       break;
76     case CL_RECEIVE:
77       /* Data is here. Process it & start it heading back */
78       do_call(cp); /* This may block for a while. */
79       mr_destroy_reply(cp->args);
80       cp->args = NULL;
81       initialize_operation(cp->pending_op, mr_start_send,
82                            (char *)&cp->reply, NULL);
83       queue_operation(cp->con, CON_OUTPUT, cp->pending_op);
84       cp->action = CL_SEND;
85       break;
86     }
87 }
88
89 char *procnames[] = {
90   "noop",
91   "auth",
92   "shutdown",
93   "query",
94   "access",
95   "dcm",
96   "motd",
97 };
98
99
100 void do_call(client *cl)
101 {
102   int pn;
103   cl->reply.mr_argc = 0;
104   cl->reply.mr_status = 0;
105   cl->reply.mr_version_no = cl->args->mr_version_no;
106   if (((pn = cl->args->mr_procno) < 0) || (pn > MR_MAX_PROC))
107     {
108       com_err(whoami, 0, "procno out of range");
109       cl->reply.mr_status = MR_UNKNOWN_PROC;
110       return;
111     }
112   if (log_flags & LOG_ARGS)
113     {
114       log_args(procnames[pn], cl->args->mr_version_no,
115                cl->args->mr_argc, cl->args->mr_argv);
116     }
117   else if (log_flags & LOG_REQUESTS)
118     com_err(whoami, 0, "%s", procnames[pn]);
119
120   if ((dormant == ASLEEP || dormant == GROGGY) &&
121       pn != MR_NOOP && pn != MR_MOTD)
122     {
123       cl->reply.mr_status = MR_DOWN;
124       if (log_flags & LOG_RES)
125         com_err(whoami, MR_DOWN, "(query refused)");
126       return;
127     }
128
129   /* make sure this gets cleared before every operation */
130   dbms_errno = 0;
131
132   switch (pn)
133     {
134     case MR_NOOP:
135       cl->reply.mr_status = 0;
136       return;
137
138     case MR_AUTH:
139       do_auth(cl);
140       return;
141
142     case MR_QUERY:
143       do_retr(cl);
144       return;
145
146     case MR_ACCESS:
147       do_access(cl);
148       return;
149
150     case MR_SHUTDOWN:
151       do_shutdown(cl);
152       return;
153
154     case MR_DO_UPDATE:
155       trigger_dcm(0, 0, cl);
156       return;
157
158     case MR_MOTD:
159       get_motd(cl);
160       return;
161     }
162 }
163
164 free_rtn_tuples(client *cp)
165 {
166   returned_tuples *temp;
167   for (temp = cp->first; temp && OP_DONE(temp->op); )
168     {
169       returned_tuples *t1 = temp;
170       temp = t1->next;
171       if (t1 == cp->last)
172         cp->last = NULL;
173
174       mr_destroy_reply(t1->retval);
175       delete_operation(t1->op);
176       free(t1);
177     }
178   cp->first = temp;
179 }
180
181 retr_callback(int argc, char **argv, char *p_cp)
182 {
183   client *cp = (client *)p_cp;
184   mr_params *arg_tmp;
185   returned_tuples *tp;
186   OPERATION op_tmp;
187   char **nargv;
188   int i;
189
190   if (row_count++ >= max_row_count)
191     {
192       dbms_errno = mr_errcode = MR_NO_MEM;
193       return;
194     }
195
196   /*
197    * This takes too much advantage of the fact that
198    * serialization of the data happens during the queue operation.
199    */
200   arg_tmp = db_alloc(sizeof(mr_params));
201   tp = db_alloc(sizeof(returned_tuples));
202   nargv = malloc(argc * sizeof(char *));
203
204   op_tmp = create_operation();
205
206   if (mr_trim_args(argc, argv) == MR_NO_MEM)
207     com_err(whoami, MR_NO_MEM, "while trimming args");
208   if (log_flags & LOG_RESP)
209     log_args("return: ", cp->args->mr_version_no, argc, argv);
210
211   tp->op = op_tmp;
212   tp->retval = arg_tmp;
213   tp->next = NULL;
214
215   arg_tmp->mr_status = MR_MORE_DATA;
216   arg_tmp->mr_version_no = cp->args->mr_version_no;
217   arg_tmp->mr_argc = argc;
218   arg_tmp->mr_argv = nargv;
219   for (i = 0; i < argc; i++)
220     {
221       int len = strlen(argv[i]) + 1;
222       nargv[i] = malloc(len);
223       memcpy(nargv[i], argv[i], len);
224     }
225   arg_tmp->mr_flattened = NULL;
226   arg_tmp->mr_argl = NULL;
227
228   if (cp->last)
229     {
230       cp->last->next = tp;
231       cp->last = tp;
232     } else
233       cp->last = cp->first = tp;
234
235   reset_operation(op_tmp);
236   initialize_operation(op_tmp, mr_start_send, (char *)arg_tmp, NULL);
237   queue_operation(cp->con, CON_OUTPUT, op_tmp);
238 }
239
240 int list_users(int (*callbk)(), char *callarg)
241 {
242   char *argv[6];
243   char buf[30];
244   char buf1[30];
245   int i;
246   extern client **clients;
247   char *cp;
248   char *ctime();
249
250   for (i = 0; i < nclients; i++)
251     {
252       client *cl = clients[i];
253       if (cl->clname)
254         argv[0] = cl->clname;
255       else argv[0] = "unauthenticated";
256
257       argv[1] = inet_ntoa(cl->haddr.sin_addr);
258       argv[2] = buf;
259       sprintf(buf, "port %d", ntohs(cl->haddr.sin_port));
260       argv[3] = ctime(&cl->last_time_used);
261       cp = strchr(argv[3], '\n');
262       if (cp)
263         *cp = '\0';
264       argv[4] = buf1;
265       sprintf(buf1, "[#%d]", cl->id);
266       (*callbk)(5, argv, callarg);
267     }
268   return 0;
269 }
270
271 do_retr(client *cl)
272 {
273   char *queryname;
274
275   cl->reply.mr_argc = 0;
276   cl->reply.mr_status = 0;
277   row_count = 0;
278
279   if (cl->args->mr_argc < 1)
280     {
281       cl->reply.mr_status = MR_ARGS;
282       com_err(whoami, MR_ARGS, "got nameless query");
283       return;
284     }
285   queryname = cl->args->mr_argv[0];
286
287   if (cl->args->mr_version_no == MR_VERSION_2)
288     newqueries++;
289   else
290     oldqueries++;
291
292   if (!strcmp(queryname, "_list_users"))
293     cl->reply.mr_status = list_users(retr_callback, (char *)cl);
294   else
295     {
296       cl->reply.mr_status = mr_process_query(cl, queryname,
297                                              cl->args->mr_argc - 1,
298                                              cl->args->mr_argv + 1,
299                                              retr_callback, (char *)cl);
300     }
301   if (row_count >= max_row_count)
302     {
303       critical_alert("moirad", "attempted query %s with %d rows\n",
304                      queryname, row_count);
305     }
306
307   if (log_flags & LOG_RES)
308     com_err(whoami, 0, "Query complete.");
309 }
310
311 do_access(client *cl)
312 {
313   if (cl->args->mr_argc < 1)
314     {
315       cl->reply.mr_status = MR_ARGS;
316       com_err(whoami, MR_ARGS, "got nameless access");
317       return;
318     }
319   cl->reply.mr_argc = 0;
320
321   cl->reply.mr_status = mr_check_access(cl, cl->args->mr_argv[0],
322                                         cl->args->mr_argc - 1,
323                                         cl->args->mr_argv + 1);
324
325   com_err(whoami, 0, "Access check complete.");
326 }
327
328
329 /* trigger_dcm is also used as a followup routine to the
330  * set_server_host_override query, hence the two dummy arguments.
331  */
332
333 struct query pseudo_query = {
334   "trigger_dcm",
335   "tdcm",
336 };
337
338 int trigger_dcm(int dummy0, int dummy1, client *cl)
339 {
340   int pid;
341   char prog[128];
342
343   cl->reply.mr_argc = 0;
344
345   if ((cl->reply.mr_status = check_query_access(&pseudo_query, 0, cl)))
346     return cl->reply.mr_status;
347
348   sprintf(prog, "%s/startdcm", BIN_DIR);
349   pid = vfork();
350   switch (pid)
351     {
352     case 0:
353       execl(prog, "startdcm", 0);
354       exit(1);
355
356     case -1:
357       cl->reply.mr_status = errno;
358       return 0;
359
360     default:
361       return 0;
362     }
363 }
364
365
366 get_motd(client *cl)
367 {
368   int motd, len;
369   char buffer[1024];
370   char *arg[1];
371
372   arg[0] = buffer;
373   cl->reply.mr_status = 0;
374   motd = open(MOIRA_MOTD_FILE, 0, O_RDONLY);
375   if (motd < 0)
376     return;
377   len = read(motd, buffer, sizeof(buffer) - 1);
378   close(motd);
379   buffer[len] = 0;
380   row_count = 0;
381   retr_callback(1, arg, cl);
382   cl->reply.mr_status = 0;
383 }
This page took 0.060084 seconds and 3 git commands to generate.