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 lock_table(struct valobj *vo);
40 int readlock_table(struct valobj *vo);
41 int convert_wildcards_uppercase(char *arg);
43 extern SQLDA *sqlald(int, int, int);
44 SQLDA *mr_alloc_sqlda(void);
46 EXEC SQL WHENEVER SQLERROR DO dbmserr();
48 /* Validation Routines */
50 int validate_row(struct query *q, char *argv[], struct validate *v)
52 EXEC SQL BEGIN DECLARE SECTION;
55 EXEC SQL END DECLARE SECTION;
57 /* build where clause */
58 build_qual(v->qual, v->argc, argv, qual);
60 if (log_flags & LOG_VALID)
61 /* tell the logfile what we're doing */
62 com_err(whoami, 0, "validating row: %s", qual);
64 /* look for the record */
65 sprintf(stmt_buf, "SELECT COUNT (*) FROM %s WHERE %s",
66 table_name[q->rtable], qual);
71 rowcount = atoi(sqlbuffer[0]);
79 int validate_fields(struct query *q, char *argv[], struct valobj *vo, int n)
88 if (log_flags & LOG_VALID)
90 com_err(whoami, 0, "validating %s in %s: %s",
91 vo->namefield, table_name[vo->table], argv[vo->index]);
93 status = validate_name(argv, vo);
97 if (log_flags & LOG_VALID)
99 com_err(whoami, 0, "validating %s in %s: %s",
100 vo->idfield, table_name[vo->table], argv[vo->index]);
102 status = validate_id(q, argv, vo);
106 if (log_flags & LOG_VALID)
108 com_err(whoami, 0, "validating %s type: %s",
109 table_name[vo->table], argv[vo->index]);
111 status = validate_type(argv, vo);
115 if (log_flags & LOG_VALID)
117 com_err(whoami, 0, "validating typed data (%s): %s",
118 argv[vo->index - 1], argv[vo->index]);
120 status = validate_typedata(q, argv, vo);
124 if (log_flags & LOG_VALID)
126 com_err(whoami, 0, "validating rename %s in %s",
127 argv[vo->index], table_name[vo->table]);
129 status = validate_rename(argv, vo);
133 if (log_flags & LOG_VALID)
134 com_err(whoami, 0, "validating chars: %s", argv[vo->index]);
135 status = validate_chars(argv, vo);
139 if (log_flags & LOG_VALID)
140 com_err(whoami, 0, "validating length: %s", argv[vo->index]);
141 status = validate_len(argv, vo);
149 status = lock_table(vo);
153 status = readlock_table(vo);
157 status = convert_wildcards(argv[vo->index]);
161 status = convert_wildcards_uppercase(argv[vo->index]);
166 if (status != MR_EXISTS)
177 /* validate_chars: verify that there are no illegal characters in
178 * the string. Legal characters are printing chars other than
179 * ", *, ?, \, [ and ].
181 static int illegalchars[] = {
182 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
183 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
184 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
185 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0 - ? */
186 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* : - O */
187 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, /* P - _ */
188 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
189 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
190 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
191 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
192 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
193 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
194 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
195 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
196 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
197 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
200 int validate_chars(char *argv[], struct valobj *vo)
202 char *s = argv[vo->index];
203 EXEC SQL BEGIN DECLARE SECTION;
206 EXEC SQL END DECLARE SECTION;
208 /* check for bad characters */
211 if (illegalchars[(int)*s++])
215 /* check for length */
216 tname = table_name[vo->table];
217 cname = vo->namefield;
218 EXEC SQL SELECT data_length INTO :len FROM user_tab_columns
219 WHERE table_name = UPPER(:tname) AND column_name = UPPER(:cname);
221 if ((strlen(argv[vo->index]) > len) &&
222 strcmp(argv[vo->index], UNIQUE_LOGIN)) /* kludge... sigh */
223 return MR_ARG_TOO_LONG;
229 int validate_id(struct query *q, char *argv[], struct valobj *vo)
231 EXEC SQL BEGIN DECLARE SECTION;
232 char *name, *namefield, *idfield;
233 int id, rowcount, tbl;
234 EXEC SQL END DECLARE SECTION;
238 name = argv[vo->index];
240 namefield = vo->namefield;
241 idfield = vo->idfield;
243 if ((tbl == USERS_TABLE && !strcmp(namefield, "login")) ||
244 tbl == MACHINE_TABLE || tbl == SUBNET_TABLE || tbl == FILESYS_TABLE ||
245 tbl == LIST_TABLE || tbl == CLUSTER_TABLE || tbl == STRINGS_TABLE)
247 if (tbl == MACHINE_TABLE || tbl == SUBNET_TABLE)
249 for (c = name; *c; c++)
255 status = name_to_id(name, tbl, &id);
258 *(int *)argv[vo->index] = id;
261 else if (status == MR_NO_MATCH && tbl == STRINGS_TABLE &&
262 (q->type == APPEND || q->type == UPDATE))
264 id = add_string(name);
265 cache_entry(name, STRINGS_TABLE, id);
266 *(int *)argv[vo->index] = id;
269 else if (status == MR_NO_MATCH || status == MR_NOT_UNIQUE)
276 /* else, it's `dubu', which uses unix_uid from users */
277 EXEC SQL SELECT COUNT(*) INTO :rowcount FROM users
278 WHERE unix_uid = :name;
283 EXEC SQL SELECT users_id INTO :id FROM users
284 WHERE unix_uid = :name;
285 *(int *)argv[vo->index] = id;
290 int validate_name(char *argv[], struct valobj *vo)
292 char *name, *namefield;
295 name = argv[vo->index];
296 namefield = vo->namefield;
297 if (vo->table == SERVERS_TABLE && !strcmp(namefield, "name"))
299 for (c = name; *c; c++)
305 sprintf(stmt_buf, "SELECT DISTINCT COUNT(*) FROM %s WHERE %s.%s = '%s'",
306 table_name[vo->table], table_name[vo->table], namefield, name);
311 return (atoi(sqlbuffer[0]) == 1) ? MR_EXISTS : vo->error;
314 int validate_rename(char *argv[], struct valobj *vo)
316 EXEC SQL BEGIN DECLARE SECTION;
317 char *name, *namefield, *idfield;
319 EXEC SQL END DECLARE SECTION;
323 status = validate_chars(argv, vo);
324 if (status != MR_EXISTS)
326 name = argv[vo->index];
327 /* minor kludge to upcasify machine names */
328 if (vo->table == MACHINE_TABLE)
330 for (c = name; *c; c++)
336 namefield = vo->namefield;
337 idfield = vo->idfield;
341 if (!strcmp(argv[vo->index], argv[vo->index - 1]))
343 sprintf(stmt_buf, "SELECT %s FROM %s WHERE %s = '%s'",
344 namefield, table_name[vo->table], namefield, name);
349 if (sqlca.sqlcode == SQL_NO_MATCH)
350 return MR_EXISTS; /* how's _that_ for intuitive? */
354 status = name_to_id(name, vo->table, &id);
355 if (status == MR_NO_MATCH || id == *(int *)argv[vo->index - 1])
362 int validate_type(char *argv[], struct valobj *vo)
364 EXEC SQL BEGIN DECLARE SECTION;
368 EXEC SQL END DECLARE SECTION;
371 typename = vo->namefield;
372 c = val = argv[vo->index];
375 if (illegalchars[(int)*c++])
379 /* uppercase type fields */
380 for (c = val; *c; c++)
386 EXEC SQL SELECT COUNT(trans) INTO :cnt FROM alias
387 WHERE name = :typename AND type = 'TYPE' AND trans = :val;
390 return cnt ? MR_EXISTS : vo->error;
393 /* validate member or type-specific data field */
395 int validate_typedata(struct query *q, char *argv[], struct valobj *vo)
397 EXEC SQL BEGIN DECLARE SECTION;
402 EXEC SQL END DECLARE SECTION;
406 /* get named object */
407 name = argv[vo->index];
409 /* get field type string (known to be at index-1) */
410 field_type = argv[vo->index - 1];
412 /* get corresponding data type associated with field type name */
413 EXEC SQL SELECT trans INTO :data_type FROM alias
414 WHERE name = :field_type AND type = 'TYPEDATA';
417 if (sqlca.sqlerrd[2] != 1)
420 /* now retrieve the record id corresponding to the named object */
421 if (strchr(data_type, ' '))
422 *strchr(data_type, ' ') = '\0';
423 if (!strcmp(data_type, "user"))
426 if (strchr(name, '@'))
428 status = name_to_id(name, USERS_TABLE, &id);
429 if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
434 else if (!strcmp(data_type, "list"))
437 status = name_to_id(name, LIST_TABLE, &id);
438 if (status && status == MR_NOT_UNIQUE)
440 if (status == MR_NO_MATCH)
442 /* if idfield is non-zero, then if argv[0] matches the string
443 * that we're trying to resolve, we should get the value of
444 * numvalues.[idfield] for the id.
446 if (vo->idfield && !strcmp(argv[0], argv[vo->index]))
448 set_next_object_id(q->validate->object_id, q->rtable, 0);
450 EXEC SQL SELECT value INTO :id FROM numvalues
452 if (sqlca.sqlerrd[2] != 1)
461 else if (!strcmp(data_type, "machine"))
464 for (c = name; *c; c++)
469 status = name_to_id(name, MACHINE_TABLE, &id);
470 if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
475 else if (!strcmp(data_type, "string"))
478 status = name_to_id(name, STRINGS_TABLE, &id);
479 if (status && status == MR_NOT_UNIQUE)
481 if (status == MR_NO_MATCH)
483 if (q->type != APPEND && q->type != UPDATE)
485 id = add_string(name);
486 cache_entry(name, STRINGS_TABLE, id);
491 else if (!strcmp(data_type, "none"))
496 /* now set value in argv */
497 *(int *)argv[vo->index] = id;
503 /* Make sure the data fits in the field */
504 int validate_len(char *argv[], struct valobj *vo)
506 EXEC SQL BEGIN DECLARE SECTION;
509 EXEC SQL END DECLARE SECTION;
511 tname = table_name[vo->table];
512 cname = vo->namefield;
513 EXEC SQL SELECT data_length INTO :len FROM user_tab_columns
514 WHERE table_name = UPPER(:tname) AND column_name = UPPER(:cname);
516 if ((strlen(argv[vo->index]) > len) &&
517 strcmp(argv[vo->index], UNIQUE_LOGIN)) /* kludge... sigh */
518 return MR_ARG_TOO_LONG;
523 /* Lock the table named by the validation object */
525 int lock_table(struct valobj *vo)
528 sprintf(stmt_buf, "LOCK TABLE %s IN EXCLUSIVE MODE", table_name[vo->table]);
529 EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
538 * Get a read lock on the table by accessing the magic lock
539 * record. Certain tables are constructed so that they contain
540 * an id field whose value is zero and a modtime field. We
541 * manipulate the modtime field of the id 0 record to effect
542 * locking of the table
545 int readlock_table(struct valobj *vo)
548 sprintf(stmt_buf, "LOCK TABLE %s IN SHARE MODE", table_name[vo->table]);
549 EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
556 return MR_EXISTS; /* validate_fields expects us to return
557 * this value if everything went okay
561 /* Check the database at startup time. */
563 void sanity_check_database(void)
565 EXEC SQL BEGIN DECLARE SECTION;
567 EXEC SQL END DECLARE SECTION;
569 /* Sometimes a crash can leave strings_id in numvalues in an
570 incorrect state. Check for that and fix it. */
572 EXEC SQL SELECT value INTO :oid FROM numvalues WHERE name = 'strings_id';
574 for (id = oid + 1; sqlca.sqlcode == 0; id++)
576 EXEC SQL SELECT string_id INTO :id FROM strings
577 WHERE string_id = :id;
581 EXEC SQL UPDATE numvalues SET value = :id - 1 WHERE name = 'strings_id';
585 char *sqlbuffer[QMAXARGS];
587 /* Dynamic SQL support routines */
588 SQLDA *mr_alloc_sqlda(void)
593 it = sqlald(QMAXARGS, ARGLEN, 0);
596 com_err(whoami, MR_NO_MEM, "setting up SQLDA");
600 for (j = 0; j < QMAXARGS; j++)
602 it->V[j] = sqlbuffer[j] = malloc(ARGLEN);
603 it->T[j] = 97; /* 97 = CHARZ = null-terminated string */
611 /* Convert normal Unix-style wildcards to SQL voodoo */
612 int convert_wildcards(char *arg)
614 static char buffer[ARGLEN];
617 for (d = buffer, s = arg; *s; s++)
644 /* Copy back into argv */
650 /* This version includes uppercase conversion, for things like gmac.
651 * This is necessary because "LIKE" doesn't work with "uppercase()".
652 * Including it in a wildcard routine saves making two passes over
653 * the argument string.
655 int convert_wildcards_uppercase(char *arg)
657 static char buffer[ARGLEN];
660 for (d = buffer, s = arg; *s; s++)
681 *d++ = toupper(*s); /* This is the only diff. */
687 /* Copy back into argv */
694 /* Adds a string to the string table. Returns the id number.
697 int add_string(char *nm)
699 EXEC SQL BEGIN DECLARE SECTION;
702 EXEC SQL END DECLARE SECTION;
704 EXEC SQL SELECT value INTO :id FROM numvalues WHERE name = 'strings_id';
706 EXEC SQL UPDATE numvalues SET value = :id WHERE name = 'strings_id';
708 EXEC SQL INSERT INTO strings (string_id, string) VALUES (:id, :name);