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;
160 /* check for bad characters */
163 if (illegalchars[(int)*s++])
167 /* check for length */
168 tname = table_name[vo->table];
169 cname = vo->namefield;
170 EXEC SQL SELECT data_length INTO :len FROM user_tab_columns
171 WHERE table_name = UPPER(:tname) AND column_name = UPPER(:cname);
173 if ((strlen(argv[vo->index]) > len) &&
174 strcmp(argv[vo->index], UNIQUE_LOGIN)) /* kludge... sigh */
175 return MR_ARG_TOO_LONG;
181 int validate_id(struct query *q, char *argv[], struct valobj *vo)
183 EXEC SQL BEGIN DECLARE SECTION;
184 char *name, *namefield, *idfield;
185 int id, rowcount, tbl;
186 EXEC SQL END DECLARE SECTION;
190 name = argv[vo->index];
192 namefield = vo->namefield;
193 idfield = vo->idfield;
195 if (tbl == MACHINE_TABLE || tbl == SUBNET_TABLE)
197 for (c = name; *c; c++)
203 status = name_to_id(name, tbl, &id);
206 *(int *)argv[vo->index] = id;
209 else if (status == MR_NO_MATCH && tbl == STRINGS_TABLE &&
210 (q->type == APPEND || q->type == UPDATE))
212 if (strlen(name) >= STRINGS_STRING_SIZE)
213 return MR_ARG_TOO_LONG;
214 id = add_string(name);
215 *(int *)argv[vo->index] = id;
218 else if (status == MR_NO_MATCH || status == MR_NOT_UNIQUE)
224 int validate_name(char *argv[], struct valobj *vo)
226 char *name, *namefield;
229 name = argv[vo->index];
230 namefield = vo->namefield;
231 if (vo->table == SERVERS_TABLE && !strcmp(namefield, "name"))
233 for (c = name; *c; c++)
241 sprintf(stmt_buf, "SELECT DISTINCT COUNT(*) FROM %s WHERE %s.%s = '%s'",
242 table_name[vo->table], table_name[vo->table], namefield, name);
247 return (atoi(sqlbuffer[0]) == 1) ? MR_EXISTS : vo->error;
250 int validate_rename(char *argv[], struct valobj *vo)
252 EXEC SQL BEGIN DECLARE SECTION;
253 char *name, *namefield, *idfield;
255 EXEC SQL END DECLARE SECTION;
259 status = validate_chars(argv, vo);
260 if (status != MR_EXISTS)
262 name = argv[vo->index];
263 /* minor kludge to upcasify machine names */
264 if (vo->table == MACHINE_TABLE)
266 for (c = name; *c; c++)
274 namefield = vo->namefield;
275 idfield = vo->idfield;
279 if (!strcmp(argv[vo->index], argv[vo->index - 1]))
281 sprintf(stmt_buf, "SELECT %s FROM %s WHERE %s = '%s'",
282 namefield, table_name[vo->table], namefield, name);
287 if (sqlca.sqlcode == SQL_NO_MATCH)
288 return MR_EXISTS; /* how's _that_ for intuitive? */
292 status = name_to_id(name, vo->table, &id);
293 if (status == MR_NO_MATCH || id == *(int *)argv[vo->index - 1])
300 int validate_type(char *argv[], struct valobj *vo)
302 EXEC SQL BEGIN DECLARE SECTION;
306 EXEC SQL END DECLARE SECTION;
309 typename = vo->namefield;
310 c = val = argv[vo->index];
313 if (illegalchars[(int)*c++])
317 /* uppercase type fields */
318 for (c = val; *c; c++)
324 EXEC SQL SELECT COUNT(trans) INTO :cnt FROM alias
325 WHERE name = :typename AND type = 'TYPE' AND trans = :val;
328 return cnt ? MR_EXISTS : vo->error;
331 /* validate member or type-specific data field */
333 int validate_typedata(struct query *q, char *argv[], struct valobj *vo)
335 EXEC SQL BEGIN DECLARE SECTION;
340 EXEC SQL END DECLARE SECTION;
344 /* get named object */
345 name = argv[vo->index];
347 /* get field type string (known to be at index-1) */
348 field_type = argv[vo->index - 1];
350 /* get corresponding data type associated with field type name */
351 EXEC SQL SELECT trans INTO :data_type FROM alias
352 WHERE name = :field_type AND type = 'TYPEDATA';
355 if (sqlca.sqlerrd[2] != 1)
358 /* now retrieve the record id corresponding to the named object */
359 if (strchr(data_type, ' '))
360 *strchr(data_type, ' ') = '\0';
361 if (!strcmp(data_type, "user"))
364 if (strchr(name, '@'))
366 status = name_to_id(name, USERS_TABLE, &id);
367 if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
372 else if (!strcmp(data_type, "list"))
375 status = name_to_id(name, LIST_TABLE, &id);
376 if (status && status == MR_NOT_UNIQUE)
378 if (status == MR_NO_MATCH)
380 /* if idfield is non-zero, then if argv[0] matches the string
381 * that we're trying to resolve, we should get the value of
382 * numvalues.[idfield] for the id.
384 if (vo->idfield && (*(int *)argv[0] == *(int *)argv[vo->index]))
386 set_next_object_id(q->validate->object_id, q->rtable, 0);
388 EXEC SQL SELECT value INTO :id FROM numvalues
390 if (sqlca.sqlerrd[2] != 1)
399 else if (!strcmp(data_type, "machine"))
402 for (c = name; *c; c++)
407 status = name_to_id(name, MACHINE_TABLE, &id);
408 if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
413 else if (!strcmp(data_type, "string"))
416 status = name_to_id(name, STRINGS_TABLE, &id);
417 if (status && status == MR_NOT_UNIQUE)
419 if (status == MR_NO_MATCH)
421 if (q->type != APPEND && q->type != UPDATE)
423 if (strlen(name) >= STRINGS_STRING_SIZE)
424 return MR_ARG_TOO_LONG;
425 id = add_string(name);
430 else if (!strcmp(data_type, "none") || !strcmp(data_type, "all"))
435 /* now set value in argv */
436 *(int *)argv[vo->index] = id;
442 /* Make sure the data fits in the field */
443 int validate_len(char *argv[], struct valobj *vo)
445 EXEC SQL BEGIN DECLARE SECTION;
448 EXEC SQL END DECLARE SECTION;
450 tname = table_name[vo->table];
451 cname = vo->namefield;
452 EXEC SQL SELECT data_length INTO :len FROM user_tab_columns
453 WHERE table_name = UPPER(:tname) AND column_name = UPPER(:cname);
455 if ((strlen(argv[vo->index]) > len) &&
456 strcmp(argv[vo->index], UNIQUE_LOGIN)) /* kludge... sigh */
457 return MR_ARG_TOO_LONG;
462 /* Make sure the data is numeric */
463 int validate_num(char *argv[], struct valobj *vo)
465 char *p = argv[vo->index];
467 if (!strcmp(p, UNIQUE_GID) || !strcmp(p, UNIQUE_UID))
480 if (*p < '0' || *p > '9')
487 /* Check the database at startup time. */
489 void sanity_check_database(void)
491 EXEC SQL BEGIN DECLARE SECTION;
493 EXEC SQL END DECLARE SECTION;
495 /* Sometimes a crash can leave strings_id in numvalues in an
496 incorrect state. Check for that and fix it. */
498 EXEC SQL SELECT value INTO :oid FROM numvalues WHERE name = 'strings_id';
500 for (id = oid + 1; sqlca.sqlcode == 0; id++)
502 EXEC SQL SELECT string_id INTO :id FROM strings
503 WHERE string_id = :id;
507 EXEC SQL UPDATE numvalues SET value = :id - 1 WHERE name = 'strings_id';
511 char *sqlbuffer[QMAXARGS];
513 /* Dynamic SQL support routines */
514 SQLDA *mr_alloc_sqlda(void)
519 it = sqlald(QMAXARGS, ARGLEN, 0);
522 com_err(whoami, MR_NO_MEM, "setting up SQLDA");
526 for (j = 0; j < QMAXARGS; j++)
528 it->V[j] = sqlbuffer[j] = xmalloc(ARGLEN);
529 it->T[j] = 97; /* 97 = CHARZ = null-terminated string */
536 /* Adds a string to the string table. Returns the id number.
539 int add_string(char *nm)
541 EXEC SQL BEGIN DECLARE SECTION;
544 EXEC SQL END DECLARE SECTION;
546 EXEC SQL SELECT value INTO :id FROM numvalues WHERE name = 'strings_id';
548 EXEC SQL UPDATE numvalues SET value = :id WHERE name = 'strings_id';
550 EXEC SQL INSERT INTO strings (string_id, string) VALUES (:id, :name);