SQLDA *mr_sqlda;
EXEC SQL BEGIN DECLARE SECTION;
-int mr_sig_length;
char stmt_buf[MR_STMTBUF_LEN];
+int proxy_acl;
EXEC SQL END DECLARE SECTION;
char *Argv[QMAXARGS];
EXEC SQL END DECLARE SECTION;
extern char *whoami;
extern FILE *journal;
+extern int QueryCount, max_version;
+extern struct query Queries[];
+
+/* Put this in a variable so that we can patch it if necessary */
+int max_row_count = 8192;
int mr_verify_query(client *cl, struct query *q, int argc, char *argv_ro[]);
int do_retrieve(struct query *q, char *pqual,
sqlglm(err_msg, &bufsize, &msglength);
err_msg[msglength] = 0;
com_err(whoami, 0, "SQL error text = %s", err_msg);
- critical_alert("MOIRA", "Moira server encountered DBMS ERROR %d\n%s",
+ critical_alert(whoami, "MOIRA", "Moira server encountered DBMS ERROR %d\n%s",
dbms_errno, err_msg);
}
int mr_open_database(void)
{
int i;
- static first_open = 1;
+ static int first_open = 1;
if (first_open)
{
first_open = 0;
/* initialize local argv */
- for (i = 0; i < 16; i++)
+ for (i = 0; i < QMAXARGS; i++)
Argv[i] = xmalloc(MAX_FIELD_WIDTH);
mr_sqlda = mr_alloc_sqlda();
incremental_init();
- flush_cache();
}
dbms_errno = 0;
if (dbms_errno)
return mr_errcode;
- EXEC SQL SELECT data_length INTO :mr_sig_length FROM user_tab_columns
- WHERE table_name = 'USERS' and column_name = 'SIGNATURE';
- EXEC SQL COMMIT WORK;
+ EXEC SQL SELECT list_id INTO :proxy_acl FROM capacls
+ WHERE capability = 'proxy';
if (dbms_errno)
return mr_errcode;
void mr_close_database(void)
{
- flush_cache();
EXEC SQL COMMIT RELEASE;
}
dbms_errno = 0;
mr_errcode = 0;
- q = get_query_by_name(name);
+ q = get_query_by_name(name, cl->version);
if (!q)
return MR_NO_HANDLE;
/* list queries command */
if (!strcmp(name, "_list_queries"))
{
- list_queries(action, actarg);
+ list_queries(cl, action, actarg);
return MR_SUCCESS;
}
{
if (argc < 1)
return MR_ARGS;
- q = get_query_by_name(argv_ro[0]);
+ q = get_query_by_name(argv_ro[0], cl->version);
if (!q)
return MR_NO_HANDLE;
help_query(q, action, actarg);
}
/* get query structure, return error if named query does not exist */
- q = get_query_by_name(name);
+ q = get_query_by_name(name, cl->version);
if (!q)
return MR_NO_HANDLE;
v = q->validate;
switch (q->type)
{
- case RETRIEVE:
+ case MR_Q_RETRIEVE:
/* for queries that do not permit wildcarding, check if row
uniquely exists */
if (v && v->field)
status = do_retrieve(q, qual, sq_save_args, sq);
if (status != MR_SUCCESS)
{
+ char **argv;
+ int i;
+
+ while (sq_get_data(sq, &argv))
+ {
+ for (i = 0; i < q->vcnt; i++)
+ free(argv[i]);
+ free(argv);
+ }
sq_destroy(sq);
break;
}
break;
- case UPDATE:
+ case MR_Q_UPDATE:
/* see if row already exists */
if (v->field)
{
incremental_after(q->rtable, qual, argv_ro);
if (status != MR_SUCCESS)
break;
- flush_name(argv_ro[0], q->rtable);
table = table_name[q->rtable];
if (strcmp(q->shortname, "sshi") && strcmp(q->shortname, "ssif"))
{
break;
- case APPEND:
+ case MR_Q_APPEND:
/* see if row already exists */
if (v->field)
{
status = (*v->post_rtn)(q, Argv, cl);
break;
- case DELETE:
+ case MR_Q_DELETE:
/* see if row already exists */
if (v->field)
{
incremental_clear_after();
if (status != MR_SUCCESS)
break;
- flush_name(argv_ro[0], q->rtable);
EXEC SQL UPDATE tblstats
SET deletes = deletes + 1, modtime = SYSDATE
WHERE table_name = :table;
status = (*v->post_rtn)(q, Argv, cl);
break;
- case SPECIAL:
+ case MR_Q_SPECIAL:
break;
}
status = mr_errcode;
}
- if (q->type == RETRIEVE)
+ if (q->type == MR_Q_RETRIEVE)
EXEC SQL COMMIT WORK;
else
{
}
else
{
- cache_abort();
EXEC SQL ROLLBACK WORK;
incremental_flush();
}
}
- cache_commit(); /* commit following abort is safe */
if (status != MR_SUCCESS)
com_err(whoami, status, " (Query failed)");
while (*fmt)
{
- if (!like && !arg)
+
+ if ((!like && !arg) || argc == 0)
{
/* only plain text remains */
strcpy(res, fmt);
}
/* if no pattern characters, write over "LIKE" with " = " */
- if (!pattern)
+ if (!pattern && !escape)
memcpy(likepos, " = ", 4);
fmt = arg + 2;
- while (*fmt != ' ')
+ while (*fmt && *fmt != ' ')
*res++ = *fmt++;
if (escape)
/* check argument count */
argreq = q->argc;
- if (q->type == UPDATE || q->type == APPEND)
+ if (q->type == MR_Q_UPDATE || q->type == MR_Q_APPEND)
argreq += q->vcnt;
if (argc != argreq)
return MR_ARGS;
if (*fr)
return MR_ARG_TOO_LONG;
*to = '\0';
-
- if (to > Argv[i] && *--to == '\\')
- return MR_BAD_CHAR;
}
- /* check initial query access */
+ /* Check initial query access. If we're acting as a proxy, only allow
+ * access if the query has "default" as a capacl.
+ */
status = check_query_access(q, Argv, cl);
if (status != MR_SUCCESS && status != MR_PERM)
return status;
- if (status == MR_SUCCESS)
- privileged++;
+ if (status == MR_SUCCESS && (!cl->proxy_id || q->everybody))
+ privileged++;
/* validate arguments */
if (v && v->valobj)
return privileged ? MR_SUCCESS : MR_PERM;
}
-
-/* This routine caches info from the database. Each query acl is stored
- * in the query structure, and whether that acl contains everybody.
- */
-
int check_query_access(struct query *q, char *argv[], client *cl)
{
EXEC SQL BEGIN DECLARE SECTION;
if (def_uid == 0)
EXEC SQL SELECT users_id INTO :def_uid FROM users WHERE login = 'default';
- /* get query access control list */
- if (q->acl != 0)
- acl_id = q->acl;
+ name = q->shortname;
+ EXEC SQL SELECT list_id INTO :acl_id FROM capacls WHERE tag = :name;
+ if (sqlca.sqlcode < 0)
+ return MR_DBMS_ERR;
+ if (sqlca.sqlcode == SQL_NO_MATCH)
+ return MR_PERM;
+ q->acl = acl_id;
+
+ /* check for default access */
+ EXEC SQL SELECT member_id INTO :acl_id FROM imembers
+ WHERE list_id = :acl_id AND member_type = 'USER'
+ AND member_id = :def_uid;
+ if (sqlca.sqlerrd[2] == 0)
+ q->everybody = 0;
else
- {
- name = q->shortname;
- EXEC SQL SELECT list_id INTO :acl_id FROM capacls WHERE tag = :name;
- if (sqlca.sqlcode < 0)
- return MR_DBMS_ERR;
- if (sqlca.sqlcode == SQL_NO_MATCH)
- return MR_PERM;
- q->acl = acl_id;
-
- /* check for default access */
- EXEC SQL SELECT member_id INTO :acl_id FROM imembers
- WHERE list_id = :acl_id AND member_type = 'USER'
- AND member_id = :def_uid;
- if (sqlca.sqlerrd[2] == 0)
- q->everybody = 0;
- else
- q->everybody = 1;
- }
+ q->everybody = 1;
if (q->everybody)
return MR_SUCCESS;
return MR_PERM;
}
-
int find_member(char *list_type, int list_id, client *cl)
{
EXEC SQL BEGIN DECLARE SECTION;
** table - name of table objects are found in
** limit - should the ID be range limited
**
- ** - called before an APPEND operation to set the next object id to
+ ** - called before an MR_Q_APPEND operation to set the next object id to
** be used for the new record to the next free value
**
**/
starting_value = value;
while (1)
{
+#ifdef ULTRIX_ID_HOLE
+ if (limit && value > 31999 && value < 32768)
+ value = 32768;
+#endif
if (limit && value > MAX_ID_VALUE)
value = MIN_ID_VALUE;
}
-/* For now this just checks the argc's. It should also see that there
- * are no duplicate names.
- */
-
void sanity_check_queries(void)
{
int i;
int maxv = 0, maxa = 0;
- extern int QueryCount2;
- extern struct query Queries2[];
#define MAX(x, y) ((x) > (y) ? (x) : (y))
- for (i = 0; i < QueryCount2; i++)
+ for (i = 0; i < QueryCount; i++)
{
- maxv = MAX(maxv, Queries2[i].vcnt);
- maxa = MAX(maxa, Queries2[i].argc);
+ maxv = MAX(maxv, Queries[i].vcnt);
+ maxa = MAX(maxa, Queries[i].argc);
+ max_version = MAX(max_version, Queries[i].version);
}
if (MAX(maxv, maxa) > QMAXARGS)
{
mr_sqlda->L[i] = MAX_FIELD_WIDTH;
}
- while (1)
+ while (rowcount < max_row_count)
{
EXEC SQL FETCH curs USING DESCRIPTOR mr_sqlda;
if (sqlca.sqlcode)
if (mr_errcode)
return mr_errcode;
- return (rowcount == 0) ? MR_NO_MATCH : MR_SUCCESS;
+ if (rowcount == max_row_count)
+ {
+ critical_alert(whoami, "moirad", "attempted query with too many rows");
+ return MR_NO_MEM;
+ }
+ else if (rowcount == 0)
+ return MR_NO_MATCH;
+ else
+ return MR_SUCCESS;
+}
+
+/* Do a name to ID translation. Moved from cache.pc because we did away
+ * with the cache, but what this function does is still useful to us.
+ */
+
+int name_to_id(char *name, enum tables type, int *id)
+{
+ EXEC SQL BEGIN DECLARE SECTION;
+ char *iname;
+ int j;
+ EXEC SQL END DECLARE SECTION;
+
+ iname = name;
+
+ switch (type)
+ {
+ case USERS_TABLE:
+ if (strchr(iname, '@') || (strlen(iname) > 8))
+ {
+ sqlca.sqlcode = SQL_NO_MATCH;
+ break;
+ }
+ EXEC SQL SELECT users_id INTO :j FROM users WHERE login = :iname;
+ break;
+ case LIST_TABLE:
+ EXEC SQL SELECT list_id INTO :j FROM list WHERE name = :iname;
+ break;
+ case MACHINE_TABLE:
+ EXEC SQL SELECT mach_id INTO :j FROM machine WHERE name = UPPER(:iname);
+ break;
+ case SUBNET_TABLE:
+ EXEC SQL SELECT snet_id INTO :j FROM subnet WHERE name = UPPER(:iname);
+ break;
+ case CLUSTERS_TABLE:
+ EXEC SQL SELECT clu_id INTO :j FROM clusters WHERE name = :iname;
+ break;
+ case FILESYS_TABLE:
+ EXEC SQL SELECT filsys_id INTO :j FROM filesys WHERE label = :iname;
+ break;
+ case STRINGS_TABLE:
+ if (!iname[0]) /* special-case empty string */
+ {
+ *id = 0;
+ return MR_SUCCESS;
+ }
+ EXEC SQL SELECT string_id INTO :j FROM strings WHERE string = :iname;
+ break;
+ case CONTAINERS_TABLE:
+ EXEC SQL SELECT cnt_id INTO :j FROM containers WHERE LOWER(name) =
+ LOWER(:iname);
+ break;
+ default:
+ return MR_INTERNAL;
+ }
+ if (sqlca.sqlcode == SQL_NO_MATCH)
+ return MR_NO_MATCH;
+ if (sqlca.sqlerrd[2] > 1)
+ return MR_NOT_UNIQUE;
+ if (sqlca.sqlcode)
+ return MR_DBMS_ERR;
+ *id = j;
+
+ return MR_SUCCESS;
}
+/* Perform an ID to name mapping. name should be a pointer to a pointer to
+ * malloc'ed data. The buffer it refers to will be freed, and a new buffer
+ * allocated with the answer.
+ *
+ * This used to be in cache.pc, but we've removed the cache, and this function
+ * is still useful to us.
+ */
+
+int id_to_name(int id, enum tables type, char **name)
+{
+ EXEC SQL BEGIN DECLARE SECTION;
+ char iname[MAX_FIELD_WIDTH];
+ int j;
+ EXEC SQL END DECLARE SECTION;
+
+ j = id;
+
+ switch (type)
+ {
+ case USERS_TABLE:
+ EXEC SQL SELECT login INTO :iname FROM users WHERE users_id = :j;
+ break;
+ case LIST_TABLE:
+ EXEC SQL SELECT name INTO :iname FROM list WHERE list_id = :j;
+ break;
+ case MACHINE_TABLE:
+ EXEC SQL SELECT name INTO :iname FROM machine WHERE mach_id = :j;
+ break;
+ case SUBNET_TABLE:
+ EXEC SQL SELECT name INTO :iname FROM subnet WHERE snet_id = :j;
+ break;
+ case CLUSTERS_TABLE:
+ EXEC SQL SELECT name INTO :iname FROM clusters WHERE clu_id = :j;
+ break;
+ case FILESYS_TABLE:
+ EXEC SQL SELECT label INTO :iname FROM filesys WHERE filsys_id = :j;
+ break;
+ case STRINGS_TABLE:
+ EXEC SQL SELECT string INTO :iname FROM strings WHERE string_id = :j;
+ break;
+ case CONTAINERS_TABLE:
+ EXEC SQL SELECT name INTO :iname FROM containers WHERE cnt_id = :j;
+ break;
+ default:
+ return MR_INTERNAL;
+ }
+ if (sqlca.sqlcode == SQL_NO_MATCH)
+ {
+ free(*name);
+ sprintf(iname, "#%d", j);
+ *name = xstrdup(iname);
+ return MR_NO_MATCH;
+ }
+ if (sqlca.sqlerrd[2] > 1)
+ return MR_INTERNAL;
+ if (sqlca.sqlcode)
+ return MR_DBMS_ERR;
+ free(*name);
+ *name = xstrdup(strtrim(iname));
+
+ return MR_SUCCESS;
+}
/* eof:qrtn.dc */