3 * Argument validation routines
5 * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology
6 * For copying and distribution information, please see the file
10 #include <mit-copyright.h>
11 #include "mr_server.h"
20 EXEC SQL INCLUDE sqlca;
21 EXEC SQL INCLUDE sqlda;
25 extern char *whoami, *table_name[], *sqlbuffer[QMAXARGS];
26 extern int dbms_errno, mr_errcode;
28 EXEC SQL BEGIN DECLARE SECTION;
29 extern char stmt_buf[];
30 EXEC SQL END DECLARE SECTION;
32 int validate_chars(char *argv[], struct valobj *vo);
33 int validate_id(struct query *, char *argv[], struct valobj *vo);
34 int validate_name(char *argv[], struct valobj *vo);
35 int validate_rename(char *argv[], struct valobj *vo);
36 int validate_type(char *argv[], struct valobj *vo);
37 int validate_typedata(struct query *, char *argv[], struct valobj *vo);
38 int validate_len(char *argv[], struct valobj *vo);
39 int validate_num(char *argv[], struct valobj *vo);
41 extern SQLDA *sqlald(int, int, int);
42 SQLDA *mr_alloc_sqlda(void);
44 EXEC SQL WHENEVER SQLERROR DO dbmserr();
46 /* Validation Routines */
48 int validate_row(struct query *q, char *argv[], struct validate *v)
50 EXEC SQL BEGIN DECLARE SECTION;
52 EXEC SQL END DECLARE SECTION;
55 /* build where clause */
56 qual = build_qual(v->qual, v->argc, argv);
58 /* look for the record */
59 sprintf(stmt_buf, "SELECT COUNT (*) FROM %s WHERE %s",
60 table_name[q->rtable], qual);
66 rowcount = atoi(sqlbuffer[0]);
74 int validate_fields(struct query *q, char *argv[], struct valobj *vo, int n)
83 status = validate_name(argv, vo);
87 status = validate_id(q, argv, vo);
91 status = validate_type(argv, vo);
95 status = validate_typedata(q, argv, vo);
99 status = validate_rename(argv, vo);
103 status = validate_chars(argv, vo);
107 status = validate_len(argv, vo);
111 status = validate_num(argv, vo);
115 if (status != MR_EXISTS)
126 /* validate_chars: verify that there are no illegal characters in
127 * the string. Legal characters are printing chars other than
128 * ", *, ?, \, [ and ].
130 static int illegalchars[] = {
131 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
132 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
133 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
134 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0 - ? */
135 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* : - O */
136 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, /* P - _ */
137 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
138 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
139 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
140 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
141 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
142 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
143 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
144 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
145 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
146 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
149 int validate_chars(char *argv[], struct valobj *vo)
151 char *s = argv[vo->index];
152 EXEC SQL BEGIN DECLARE SECTION;
155 EXEC SQL END DECLARE SECTION;
157 /* check for bad characters */
160 if (illegalchars[(int)*s++])
164 /* check for length */
165 tname = table_name[vo->table];
166 cname = vo->namefield;
167 EXEC SQL SELECT data_length INTO :len FROM user_tab_columns
168 WHERE table_name = UPPER(:tname) AND column_name = UPPER(:cname);
170 if ((strlen(argv[vo->index]) > len) &&
171 strcmp(argv[vo->index], UNIQUE_LOGIN)) /* kludge... sigh */
172 return MR_ARG_TOO_LONG;
178 int validate_id(struct query *q, char *argv[], struct valobj *vo)
180 EXEC SQL BEGIN DECLARE SECTION;
181 char *name, *namefield, *idfield;
182 int id, rowcount, tbl;
183 EXEC SQL END DECLARE SECTION;
187 name = argv[vo->index];
189 namefield = vo->namefield;
190 idfield = vo->idfield;
192 if (tbl == MACHINE_TABLE || tbl == SUBNET_TABLE)
194 for (c = name; *c; c++)
200 status = name_to_id(name, tbl, &id);
203 *(int *)argv[vo->index] = id;
206 else if (status == MR_NO_MATCH && tbl == STRINGS_TABLE &&
207 (q->type == APPEND || q->type == UPDATE))
209 if (strlen(name) >= STRINGS_STRING_SIZE)
210 return MR_ARG_TOO_LONG;
211 id = add_string(name);
212 *(int *)argv[vo->index] = id;
215 else if (status == MR_NO_MATCH || status == MR_NOT_UNIQUE)
221 int validate_name(char *argv[], struct valobj *vo)
223 char *name, *namefield;
226 name = argv[vo->index];
227 namefield = vo->namefield;
228 if (vo->table == SERVERS_TABLE && !strcmp(namefield, "name"))
230 for (c = name; *c; c++)
238 sprintf(stmt_buf, "SELECT DISTINCT COUNT(*) FROM %s WHERE %s.%s = '%s'",
239 table_name[vo->table], table_name[vo->table], namefield, name);
244 return (atoi(sqlbuffer[0]) == 1) ? MR_EXISTS : vo->error;
247 int validate_rename(char *argv[], struct valobj *vo)
249 EXEC SQL BEGIN DECLARE SECTION;
250 char *name, *namefield, *idfield;
252 EXEC SQL END DECLARE SECTION;
256 status = validate_chars(argv, vo);
257 if (status != MR_EXISTS)
259 name = argv[vo->index];
260 /* minor kludge to upcasify machine names */
261 if (vo->table == MACHINE_TABLE)
263 for (c = name; *c; c++)
271 namefield = vo->namefield;
272 idfield = vo->idfield;
276 if (!strcmp(argv[vo->index], argv[vo->index - 1]))
278 sprintf(stmt_buf, "SELECT %s FROM %s WHERE %s = '%s'",
279 namefield, table_name[vo->table], namefield, name);
284 if (sqlca.sqlcode == SQL_NO_MATCH)
285 return MR_EXISTS; /* how's _that_ for intuitive? */
289 status = name_to_id(name, vo->table, &id);
290 if (status == MR_NO_MATCH || id == *(int *)argv[vo->index - 1])
297 int validate_type(char *argv[], struct valobj *vo)
299 EXEC SQL BEGIN DECLARE SECTION;
303 EXEC SQL END DECLARE SECTION;
306 typename = vo->namefield;
307 c = val = argv[vo->index];
310 if (illegalchars[(int)*c++])
314 /* uppercase type fields */
315 for (c = val; *c; c++)
321 EXEC SQL SELECT COUNT(trans) INTO :cnt FROM alias
322 WHERE name = :typename AND type = 'TYPE' AND trans = :val;
325 return cnt ? MR_EXISTS : vo->error;
328 /* validate member or type-specific data field */
330 int validate_typedata(struct query *q, char *argv[], struct valobj *vo)
332 EXEC SQL BEGIN DECLARE SECTION;
337 EXEC SQL END DECLARE SECTION;
341 /* get named object */
342 name = argv[vo->index];
344 /* get field type string (known to be at index-1) */
345 field_type = argv[vo->index - 1];
347 /* get corresponding data type associated with field type name */
348 EXEC SQL SELECT trans INTO :data_type FROM alias
349 WHERE name = :field_type AND type = 'TYPEDATA';
352 if (sqlca.sqlerrd[2] != 1)
355 /* now retrieve the record id corresponding to the named object */
356 if (strchr(data_type, ' '))
357 *strchr(data_type, ' ') = '\0';
358 if (!strcmp(data_type, "user"))
361 if (strchr(name, '@'))
363 status = name_to_id(name, USERS_TABLE, &id);
364 if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
369 else if (!strcmp(data_type, "list"))
372 status = name_to_id(name, LIST_TABLE, &id);
373 if (status && status == MR_NOT_UNIQUE)
375 if (status == MR_NO_MATCH)
377 /* if idfield is non-zero, then if argv[0] matches the string
378 * that we're trying to resolve, we should get the value of
379 * numvalues.[idfield] for the id.
381 if (vo->idfield && (*(int *)argv[0] == *(int *)argv[vo->index]))
383 set_next_object_id(q->validate->object_id, q->rtable, 0);
385 EXEC SQL SELECT value INTO :id FROM numvalues
387 if (sqlca.sqlerrd[2] != 1)
396 else if (!strcmp(data_type, "machine"))
399 for (c = name; *c; c++)
404 status = name_to_id(name, MACHINE_TABLE, &id);
405 if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
410 else if (!strcmp(data_type, "string"))
413 status = name_to_id(name, STRINGS_TABLE, &id);
414 if (status && status == MR_NOT_UNIQUE)
416 if (status == MR_NO_MATCH)
418 if (q->type != APPEND && q->type != UPDATE)
420 if (strlen(name) >= STRINGS_STRING_SIZE)
421 return MR_ARG_TOO_LONG;
422 id = add_string(name);
427 else if (!strcmp(data_type, "none") || !strcmp(data_type, "all"))
432 /* now set value in argv */
433 *(int *)argv[vo->index] = id;
439 /* Make sure the data fits in the field */
440 int validate_len(char *argv[], struct valobj *vo)
442 EXEC SQL BEGIN DECLARE SECTION;
445 EXEC SQL END DECLARE SECTION;
447 tname = table_name[vo->table];
448 cname = vo->namefield;
449 EXEC SQL SELECT data_length INTO :len FROM user_tab_columns
450 WHERE table_name = UPPER(:tname) AND column_name = UPPER(:cname);
452 if ((strlen(argv[vo->index]) > len) &&
453 strcmp(argv[vo->index], UNIQUE_LOGIN)) /* kludge... sigh */
454 return MR_ARG_TOO_LONG;
459 /* Make sure the data is numeric */
460 int validate_num(char *argv[], struct valobj *vo)
462 char *p = argv[vo->index];
464 if (!strcmp(p, UNIQUE_GID) || !strcmp(p, UNIQUE_UID))
477 if (*p < '0' || *p > '9')
484 /* Check the database at startup time. */
486 void sanity_check_database(void)
488 EXEC SQL BEGIN DECLARE SECTION;
490 EXEC SQL END DECLARE SECTION;
492 /* Sometimes a crash can leave strings_id in numvalues in an
493 incorrect state. Check for that and fix it. */
495 EXEC SQL SELECT value INTO :oid FROM numvalues WHERE name = 'strings_id';
497 for (id = oid + 1; sqlca.sqlcode == 0; id++)
499 EXEC SQL SELECT string_id INTO :id FROM strings
500 WHERE string_id = :id;
504 EXEC SQL UPDATE numvalues SET value = :id - 1 WHERE name = 'strings_id';
508 char *sqlbuffer[QMAXARGS];
510 /* Dynamic SQL support routines */
511 SQLDA *mr_alloc_sqlda(void)
516 it = sqlald(QMAXARGS, ARGLEN, 0);
519 com_err(whoami, MR_NO_MEM, "setting up SQLDA");
523 for (j = 0; j < QMAXARGS; j++)
525 it->V[j] = sqlbuffer[j] = xmalloc(ARGLEN);
526 it->T[j] = 97; /* 97 = CHARZ = null-terminated string */
533 /* Adds a string to the string table. Returns the id number.
536 int add_string(char *nm)
538 EXEC SQL BEGIN DECLARE SECTION;
541 EXEC SQL END DECLARE SECTION;
543 EXEC SQL SELECT value INTO :id FROM numvalues WHERE name = 'strings_id';
545 EXEC SQL UPDATE numvalues SET value = :id WHERE name = 'strings_id';
547 EXEC SQL INSERT INTO strings (string_id, string) VALUES (:id, :name);