-/*
- * $Source$
- * $Author$
- * $Header$
+/* $Id$
*
- * Copyright (C) 1987 by the Massachusetts Institute of Technology
+ * Do RPC
*
- * $Log$
- * Revision 1.3 1987-06-04 01:35:01 wesommer
- * Added a working query request handler.
+ * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology
+ * For copying and distribution information, please see the file
+ * <mit-copyright.h>.
*
- * Revision 1.2 87/06/03 16:07:50 wesommer
- * Fixes for lint.
- *
- * Revision 1.1 87/06/02 20:07:10 wesommer
- * Initial revision
- *
*/
-#ifndef lint
-static char *rcsid_sms_scall_c = "$Header$";
-#endif lint
+#include <mit-copyright.h>
+#include "mr_server.h"
+#include "query.h"
+
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
-#include <krb.h>
#include <errno.h>
-#include "sms_private.h"
-#include "sms_server.h"
-extern char buf1[];
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+RCSID("$Header$");
+
extern int nclients;
+extern client **clients;
extern char *whoami;
-extern void clist_delete(), do_auth(), do_shutdown();
-void do_call();
+extern int dbms_errno, mr_errcode;
-/*
- * Welcome to the (finite state) machine (highest level).
- */
-void
-do_client(cp)
- client *cp;
-{
- if (OP_STATUS(cp->pending_op) == OP_CANCELLED) {
- (void) sprintf(buf1, "Closed connection (now %d client%s)",
- nclients-1,
- nclients!=2?"s":"");
- com_err(whoami, 0, buf1);
- clist_delete(cp);
- return;
- }
- switch (cp->action) {
- case CL_ACCEPT:
- case CL_SEND:
- /* Start recieving next request */
- initialize_operation(cp->pending_op, sms_start_recv,
- (char *)&cp->args, (int (*)())NULL);
- queue_operation(cp->con, CON_INPUT, cp->pending_op);
- cp->action = CL_RECEIVE;
- break;
- case CL_RECEIVE:
- /* Data is here. Process it & start it heading back */
- do_call(cp); /* This may block for a while. */
- initialize_operation(cp->pending_op, sms_start_send,
- (char *)&cp->reply, (int (*)())NULL);
- queue_operation(cp->con, CON_OUTPUT, cp->pending_op);
- cp->action = CL_SEND;
- break;
- }
-}
+int max_version;
+
+void do_call(client *cl);
+void free_rtn_tuples(client *cp);
+int retr_callback(int argc, char **argv, void *p_cl);
+int list_users(client *cl);
+void do_retr(client *cl);
+void do_access(client *cl);
+void get_motd(client *cl);
+void do_version(client *cl);
-#ifdef notdef
char *procnames[] = {
- "noop",
- "auth",
- "shutdown",
- "query",
- };
-#endif notdef
-
-void
-do_call(cl)
- client *cl;
+ "noop",
+ "auth",
+ "shutdown",
+ "query",
+ "access",
+ "dcm",
+ "motd",
+ "proxy",
+ "version",
+ "auth_krb5",
+};
+
+int newqueries;
+
+void client_read(client *cl)
{
- int pn;
- cl->reply.sms_argc = 0;
- cl->reply.sms_status = 0;
- if (((pn = cl->args->sms_procno) < 0) ||
- (pn > SMS_MAX_PROC)) {
- com_err(whoami, 0, "procno out of range");
- cl->reply.sms_status = SMS_UNKNOWN_PROC;
- return;
- }
-#ifdef SMS_DBG
- fprintf(stderr, "[#%d] %s(", cl->id, procnames[pn]);
- for (i=0; i < cl->args->sms_argc; i++) {
- if (i) fputc(',', stderr);
- frequote(stderr,cl->args->sms_argv[i]);
- }
- fprintf(stderr, ")\n");
-#endif SMS_DBG
-
- switch(pn) {
- case SMS_NOOP:
- cl->reply.sms_status = 0;
- com_err(whoami, 0, "noop");
- return;
- case SMS_AUTH:
- do_auth(cl);
- return;
-
- case SMS_QUERY:
- do_retr(cl);
- return;
-
- case SMS_SHUTDOWN:
- do_shutdown(cl);
- return;
+ int status, pn;
+
+ status = mr_cont_receive(cl->con, &cl->req);
+ if (status == -1)
+ return;
+ else if (status != MR_SUCCESS)
+ {
+ cl->state = CL_CLOSING;
+ if (status != MR_NOT_CONNECTED)
+ com_err(whoami, status, "while reading from socket");
+ return;
+ }
+
+ pn = cl->req.u.mr_procno;
+ if (pn < 0 || pn > MR_MAX_PROC)
+ {
+ com_err(whoami, 0, "procno out of range");
+ client_reply(cl, MR_UNKNOWN_PROC);
+ goto out;
+ }
+ log_args(procnames[pn], 2, cl->req.mr_argc, cl->req.mr_argv);
+
+ if (dormant == ASLEEP && pn != MR_NOOP && pn != MR_MOTD)
+ {
+ client_reply(cl, MR_DOWN);
+ com_err(whoami, MR_DOWN, "(query refused)");
+ goto out;
+ }
+
+ /* make sure this gets cleared before every operation */
+ dbms_errno = 0;
+
+ switch (pn)
+ {
+ case MR_NOOP:
+ client_reply(cl, MR_SUCCESS);
+ break;
+
+ case MR_AUTH:
+ do_auth(cl);
+ break;
+
+ case MR_QUERY:
+ do_retr(cl);
+ break;
+
+ case MR_ACCESS:
+ do_access(cl);
+ break;
+
+ case MR_SHUTDOWN:
+ do_shutdown(cl);
+ break;
+
+ case MR_DO_UPDATE:
+ client_reply(cl, MR_PERM);
+ break;
+
+ case MR_MOTD:
+ get_motd(cl);
+ break;
+
+ case MR_PROXY:
+ do_proxy(cl);
+ break;
+
+ case MR_SETVERSION:
+ do_version(cl);
+ break;
+
+ case MR_KRB5_AUTH:
+ do_krb5_auth(cl);
+ break;
+
+ }
+
+out:
+ mr_destroy_reply(cl->req);
+ memset(&cl->req, 0, sizeof(mr_params));
+}
+
+/* Set the final return status for a query. We always keep one more
+ free slot in cl->tuples[] than we're using so that this can't fail */
+void client_reply(client *cl, long status)
+{
+ cl->tuples[cl->ntuples].u.mr_status = status;
+ cl->tuples[cl->ntuples].mr_argc = 0;
+ cl->tuples[cl->ntuples].mr_argl = NULL;
+ cl->tuples[cl->ntuples].mr_argv = NULL;
+ cl->ntuples++;
+}
+
+void client_return_tuple(client *cl, int argc, char **argv)
+{
+ if (cl->state == CL_CLOSING || dbms_errno)
+ return;
+
+ if (cl->ntuples == cl->tuplessize - 1)
+ {
+ int newsize = (cl->tuplessize + 4) * 2;
+ mr_params *newtuples;
+
+ newtuples = realloc(cl->tuples, newsize * sizeof(mr_params));
+ if (!newtuples)
+ {
+ free_rtn_tuples(cl);
+ dbms_errno = mr_errcode = MR_NO_MEM;
+ return;
}
+ cl->tuplessize = newsize;
+ cl->tuples = newtuples;
+ }
+
+ cl->tuples[cl->ntuples].u.mr_status = MR_MORE_DATA;
+ cl->tuples[cl->ntuples].mr_argc = argc;
+ cl->tuples[cl->ntuples].mr_argl = NULL;
+ cl->tuples[cl->ntuples].mr_argv = mr_copy_args(argv, argc);
+ cl->ntuples++;
}
-retr_callback(argc, argv, p_cp)
- int argc;
- char **argv;
- char *p_cp;
+void client_write(client *cl)
{
- register client *cp = (client *)p_cp;
- /* XXX MEM when are these freed?? */
- /*
- * This takes too much advantage of the fact that
- * serialization of the data happens during the queue operation.
- */
- sms_params *arg_tmp = (sms_params *)db_alloc(sizeof(sms_params));
- OPERATION op_tmp = create_operation();
-
-
-#ifdef notdef /* We really don't want this logged */
- com_err(whoami, 0, "Returning next data:");
- log_args(argc, argv);
-#endif notdef
-
- arg_tmp->sms_status = SMS_MORE_DATA;
- arg_tmp->sms_argc = argc;
- arg_tmp->sms_argv = argv;
- arg_tmp->sms_flattened = (char *)NULL;
- arg_tmp->sms_argl = (int *)NULL;
- reset_operation(op_tmp);
- initialize_operation(op_tmp, sms_start_send, (char *)arg_tmp,
- (int (*)())NULL);
- queue_operation(cp->con, CON_OUTPUT, op_tmp);
+ int status;
+
+ status = mr_send(cl->con, &cl->tuples[cl->nexttuple]);
+ if (status)
+ {
+ com_err(whoami, status, "writing to socket");
+ cl->state = CL_CLOSING;
+ }
+ else
+ {
+ cl->nexttuple++;
+ if (cl->nexttuple == cl->ntuples)
+ free_rtn_tuples(cl);
+ }
}
+void free_rtn_tuples(client *cl)
+{
+ for (cl->ntuples--; cl->ntuples >= 0; cl->ntuples--)
+ free_argv(cl->tuples[cl->ntuples].mr_argv,
+ cl->tuples[cl->ntuples].mr_argc);
+ free(cl->tuples);
-do_retr(cl)
- client *cl;
+ cl->tuples = xmalloc(sizeof(mr_params));
+ cl->tuplessize = 1;
+ cl->ntuples = cl->nexttuple = 0;
+}
+
+void do_retr(client *cl)
{
- cl->reply.sms_argc = 0;
- cl->reply.sms_status = 0;
+ char *queryname;
+ int status;
- if (!cl->clname) {
- com_err(whoami, 0, "Unauthenticated query rejected");
- cl->reply.sms_status = EACCES;
- return;
- }
- com_err(whoami, 0, "Processing query: ");
- log_args(cl->args->sms_argc, cl->args->sms_argv);
-
- sms_process_query(cl->args->sms_argv[0],
- cl->args->sms_argc-1,
- cl->args->sms_argv+1,
- retr_callback,
- (char *)cl);
-
- com_err(whoami, 0, "Query complete.");
+ if (cl->req.mr_argc < 1)
+ {
+ client_reply(cl, MR_ARGS);
+ com_err(whoami, MR_ARGS, "got nameless query");
+ return;
+ }
+ queryname = cl->req.mr_argv[0];
+ newqueries++;
+
+ if (!strcmp(queryname, "_list_users"))
+ status = list_users(cl);
+ else
+ status = mr_process_query(cl, queryname, cl->req.mr_argc - 1,
+ cl->req.mr_argv + 1, retr_callback, cl);
+
+ client_reply(cl, status);
+
+ com_err(whoami, 0, "Query complete.");
+}
+
+int retr_callback(int argc, char **argv, void *p_cl)
+{
+ client *cl = p_cl;
+
+ mr_trim_args(argc, argv);
+ client_return_tuple(cl, argc, argv);
+}
+
+void do_access(client *cl)
+{
+ int status;
+
+ if (cl->req.mr_argc < 1)
+ {
+ client_reply(cl, MR_ARGS);
+ com_err(whoami, MR_ARGS, "got nameless access");
+ return;
+ }
+
+ status = mr_check_access(cl, cl->req.mr_argv[0], cl->req.mr_argc - 1,
+ cl->req.mr_argv + 1);
+ client_reply(cl, status);
+
+ com_err(whoami, 0, "Access check complete.");
+}
+
+void do_version(client *cl)
+{
+ if (cl->req.mr_argc != 1)
+ {
+ client_reply(cl, MR_ARGS);
+ com_err(whoami, MR_ARGS, "incorrect number of arguments");
+ return;
+ }
+
+ cl->version = atoi(cl->req.mr_argv[0]);
+ if (cl->version == -1)
+ cl->version = max_version;
+
+ client_reply(cl, cl->version == max_version ? MR_SUCCESS :
+ cl->version < max_version ? MR_VERSION_LOW : MR_VERSION_HIGH);
+}
+
+void get_motd(client *cl)
+{
+ int motd;
+ char *buffer;
+ struct stat statb;
+
+ if (stat(MOIRA_MOTD_FILE, &statb) == -1)
+ {
+ client_reply(cl, MR_SUCCESS);
+ return;
+ }
+
+ buffer = malloc(statb.st_size + 1);
+ if (!buffer)
+ {
+ client_reply(cl, MR_NO_MEM);
+ return;
+ }
+
+ motd = open(MOIRA_MOTD_FILE, 0, O_RDONLY);
+ if (motd)
+ {
+ read(motd, buffer, statb.st_size);
+ close(motd);
+ buffer[statb.st_size] = '\0';
+ client_return_tuple(cl, 1, &buffer);
+ client_reply(cl, MR_SUCCESS);
+ }
+ else
+ client_reply(cl, errno);
+
+ free(buffer);
+}
+
+int list_users(client *cl)
+{
+ char *argv[5];
+ char buf[30];
+ char buf1[30];
+ int i;
+ char *cp;
+
+ for (i = 0; i < nclients; i++)
+ {
+ client *c = clients[i];
+ argv[0] = c->clname;
+ argv[1] = inet_ntoa(c->haddr.sin_addr);
+ argv[2] = buf;
+ sprintf(buf, "port %d", ntohs(c->haddr.sin_port));
+ argv[3] = ctime(&c->last_time_used);
+ cp = strchr(argv[3], '\n');
+ if (cp)
+ *cp = '\0';
+ argv[4] = buf1;
+ sprintf(buf1, "[#%d]", c->id);
+ client_return_tuple(cl, 5, argv);
+ }
+ return MR_SUCCESS;
}