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 /* look for the record */
61 sprintf(stmt_buf, "SELECT COUNT (*) FROM %s WHERE %s",
62 table_name[q->rtable], qual);
67 rowcount = atoi(sqlbuffer[0]);
75 int validate_fields(struct query *q, char *argv[], struct valobj *vo, int n)
84 status = validate_name(argv, vo);
88 status = validate_id(q, argv, vo);
92 status = validate_type(argv, vo);
96 status = validate_typedata(q, argv, vo);
100 status = validate_rename(argv, vo);
104 status = validate_chars(argv, vo);
108 status = validate_len(argv, vo);
116 status = lock_table(vo);
120 status = readlock_table(vo);
124 status = convert_wildcards(argv[vo->index]);
128 status = convert_wildcards_uppercase(argv[vo->index]);
133 if (status != MR_EXISTS)
144 /* validate_chars: verify that there are no illegal characters in
145 * the string. Legal characters are printing chars other than
146 * ", *, ?, \, [ and ].
148 static int illegalchars[] = {
149 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
150 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
151 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
152 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0 - ? */
153 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* : - O */
154 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, /* P - _ */
155 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
156 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
157 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
158 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
159 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
160 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
161 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
162 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
163 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
164 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
167 int validate_chars(char *argv[], struct valobj *vo)
169 char *s = argv[vo->index];
170 EXEC SQL BEGIN DECLARE SECTION;
173 EXEC SQL END DECLARE SECTION;
175 /* check for bad characters */
178 if (illegalchars[(int)*s++])
182 /* check for length */
183 tname = table_name[vo->table];
184 cname = vo->namefield;
185 EXEC SQL SELECT data_length INTO :len FROM user_tab_columns
186 WHERE table_name = UPPER(:tname) AND column_name = UPPER(:cname);
188 if ((strlen(argv[vo->index]) > len) &&
189 strcmp(argv[vo->index], UNIQUE_LOGIN)) /* kludge... sigh */
190 return MR_ARG_TOO_LONG;
196 int validate_id(struct query *q, char *argv[], struct valobj *vo)
198 EXEC SQL BEGIN DECLARE SECTION;
199 char *name, *namefield, *idfield;
200 int id, rowcount, tbl;
201 EXEC SQL END DECLARE SECTION;
205 name = argv[vo->index];
207 namefield = vo->namefield;
208 idfield = vo->idfield;
210 if ((tbl == USERS_TABLE && !strcmp(namefield, "login")) ||
211 tbl == MACHINE_TABLE || tbl == SUBNET_TABLE || tbl == FILESYS_TABLE ||
212 tbl == LIST_TABLE || tbl == CLUSTER_TABLE || tbl == STRINGS_TABLE)
214 if (tbl == MACHINE_TABLE || tbl == SUBNET_TABLE)
216 for (c = name; *c; c++)
222 status = name_to_id(name, tbl, &id);
225 *(int *)argv[vo->index] = id;
228 else if (status == MR_NO_MATCH && tbl == STRINGS_TABLE &&
229 (q->type == APPEND || q->type == UPDATE))
231 id = add_string(name);
232 cache_entry(name, STRINGS_TABLE, id);
233 *(int *)argv[vo->index] = id;
236 else if (status == MR_NO_MATCH || status == MR_NOT_UNIQUE)
243 /* else, it's `dubu', which uses unix_uid from users */
244 EXEC SQL SELECT COUNT(*) INTO :rowcount FROM users
245 WHERE unix_uid = :name;
250 EXEC SQL SELECT users_id INTO :id FROM users
251 WHERE unix_uid = :name;
252 *(int *)argv[vo->index] = id;
257 int validate_name(char *argv[], struct valobj *vo)
259 char *name, *namefield;
262 name = argv[vo->index];
263 namefield = vo->namefield;
264 if (vo->table == SERVERS_TABLE && !strcmp(namefield, "name"))
266 for (c = name; *c; c++)
272 sprintf(stmt_buf, "SELECT DISTINCT COUNT(*) FROM %s WHERE %s.%s = '%s'",
273 table_name[vo->table], table_name[vo->table], namefield, name);
278 return (atoi(sqlbuffer[0]) == 1) ? MR_EXISTS : vo->error;
281 int validate_rename(char *argv[], struct valobj *vo)
283 EXEC SQL BEGIN DECLARE SECTION;
284 char *name, *namefield, *idfield;
286 EXEC SQL END DECLARE SECTION;
290 status = validate_chars(argv, vo);
291 if (status != MR_EXISTS)
293 name = argv[vo->index];
294 /* minor kludge to upcasify machine names */
295 if (vo->table == MACHINE_TABLE)
297 for (c = name; *c; c++)
303 namefield = vo->namefield;
304 idfield = vo->idfield;
308 if (!strcmp(argv[vo->index], argv[vo->index - 1]))
310 sprintf(stmt_buf, "SELECT %s FROM %s WHERE %s = '%s'",
311 namefield, table_name[vo->table], namefield, name);
316 if (sqlca.sqlcode == SQL_NO_MATCH)
317 return MR_EXISTS; /* how's _that_ for intuitive? */
321 status = name_to_id(name, vo->table, &id);
322 if (status == MR_NO_MATCH || id == *(int *)argv[vo->index - 1])
329 int validate_type(char *argv[], struct valobj *vo)
331 EXEC SQL BEGIN DECLARE SECTION;
335 EXEC SQL END DECLARE SECTION;
338 typename = vo->namefield;
339 c = val = argv[vo->index];
342 if (illegalchars[(int)*c++])
346 /* uppercase type fields */
347 for (c = val; *c; c++)
353 EXEC SQL SELECT COUNT(trans) INTO :cnt FROM alias
354 WHERE name = :typename AND type = 'TYPE' AND trans = :val;
357 return cnt ? MR_EXISTS : vo->error;
360 /* validate member or type-specific data field */
362 int validate_typedata(struct query *q, char *argv[], struct valobj *vo)
364 EXEC SQL BEGIN DECLARE SECTION;
369 EXEC SQL END DECLARE SECTION;
373 /* get named object */
374 name = argv[vo->index];
376 /* get field type string (known to be at index-1) */
377 field_type = argv[vo->index - 1];
379 /* get corresponding data type associated with field type name */
380 EXEC SQL SELECT trans INTO :data_type FROM alias
381 WHERE name = :field_type AND type = 'TYPEDATA';
384 if (sqlca.sqlerrd[2] != 1)
387 /* now retrieve the record id corresponding to the named object */
388 if (strchr(data_type, ' '))
389 *strchr(data_type, ' ') = '\0';
390 if (!strcmp(data_type, "user"))
393 if (strchr(name, '@'))
395 status = name_to_id(name, USERS_TABLE, &id);
396 if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
401 else if (!strcmp(data_type, "list"))
404 status = name_to_id(name, LIST_TABLE, &id);
405 if (status && status == MR_NOT_UNIQUE)
407 if (status == MR_NO_MATCH)
409 /* if idfield is non-zero, then if argv[0] matches the string
410 * that we're trying to resolve, we should get the value of
411 * numvalues.[idfield] for the id.
413 if (vo->idfield && !strcmp(argv[0], argv[vo->index]))
415 set_next_object_id(q->validate->object_id, q->rtable, 0);
417 EXEC SQL SELECT value INTO :id FROM numvalues
419 if (sqlca.sqlerrd[2] != 1)
428 else if (!strcmp(data_type, "machine"))
431 for (c = name; *c; c++)
436 status = name_to_id(name, MACHINE_TABLE, &id);
437 if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
442 else if (!strcmp(data_type, "string"))
445 status = name_to_id(name, STRINGS_TABLE, &id);
446 if (status && status == MR_NOT_UNIQUE)
448 if (status == MR_NO_MATCH)
450 if (q->type != APPEND && q->type != UPDATE)
452 id = add_string(name);
453 cache_entry(name, STRINGS_TABLE, id);
458 else if (!strcmp(data_type, "none"))
463 /* now set value in argv */
464 *(int *)argv[vo->index] = id;
470 /* Make sure the data fits in the field */
471 int validate_len(char *argv[], struct valobj *vo)
473 EXEC SQL BEGIN DECLARE SECTION;
476 EXEC SQL END DECLARE SECTION;
478 tname = table_name[vo->table];
479 cname = vo->namefield;
480 EXEC SQL SELECT data_length INTO :len FROM user_tab_columns
481 WHERE table_name = UPPER(:tname) AND column_name = UPPER(:cname);
483 if ((strlen(argv[vo->index]) > len) &&
484 strcmp(argv[vo->index], UNIQUE_LOGIN)) /* kludge... sigh */
485 return MR_ARG_TOO_LONG;
490 /* Lock the table named by the validation object */
492 int lock_table(struct valobj *vo)
495 sprintf(stmt_buf, "LOCK TABLE %s IN EXCLUSIVE MODE", table_name[vo->table]);
496 EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
505 * Get a read lock on the table by accessing the magic lock
506 * record. Certain tables are constructed so that they contain
507 * an id field whose value is zero and a modtime field. We
508 * manipulate the modtime field of the id 0 record to effect
509 * locking of the table
512 int readlock_table(struct valobj *vo)
515 sprintf(stmt_buf, "LOCK TABLE %s IN SHARE MODE", table_name[vo->table]);
516 EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
523 return MR_EXISTS; /* validate_fields expects us to return
524 * this value if everything went okay
528 /* Check the database at startup time. */
530 void sanity_check_database(void)
532 EXEC SQL BEGIN DECLARE SECTION;
534 EXEC SQL END DECLARE SECTION;
536 /* Sometimes a crash can leave strings_id in numvalues in an
537 incorrect state. Check for that and fix it. */
539 EXEC SQL SELECT value INTO :oid FROM numvalues WHERE name = 'strings_id';
541 for (id = oid + 1; sqlca.sqlcode == 0; id++)
543 EXEC SQL SELECT string_id INTO :id FROM strings
544 WHERE string_id = :id;
548 EXEC SQL UPDATE numvalues SET value = :id - 1 WHERE name = 'strings_id';
552 char *sqlbuffer[QMAXARGS];
554 /* Dynamic SQL support routines */
555 SQLDA *mr_alloc_sqlda(void)
560 it = sqlald(QMAXARGS, ARGLEN, 0);
563 com_err(whoami, MR_NO_MEM, "setting up SQLDA");
567 for (j = 0; j < QMAXARGS; j++)
569 it->V[j] = sqlbuffer[j] = malloc(ARGLEN);
570 it->T[j] = 97; /* 97 = CHARZ = null-terminated string */
578 /* Convert normal Unix-style wildcards to SQL voodoo */
579 int convert_wildcards(char *arg)
581 static char buffer[ARGLEN];
584 for (d = buffer, s = arg; *s; s++)
611 /* Copy back into argv */
617 /* This version includes uppercase conversion, for things like gmac.
618 * This is necessary because "LIKE" doesn't work with "uppercase()".
619 * Including it in a wildcard routine saves making two passes over
620 * the argument string.
622 int convert_wildcards_uppercase(char *arg)
624 static char buffer[ARGLEN];
627 for (d = buffer, s = arg; *s; s++)
648 *d++ = toupper(*s); /* This is the only diff. */
654 /* Copy back into argv */
661 /* Adds a string to the string table. Returns the id number.
664 int add_string(char *nm)
666 EXEC SQL BEGIN DECLARE SECTION;
669 EXEC SQL END DECLARE SECTION;
671 EXEC SQL SELECT value INTO :id FROM numvalues WHERE name = 'strings_id';
673 EXEC SQL UPDATE numvalues SET value = :id WHERE name = 'strings_id';
675 EXEC SQL INSERT INTO strings (string_id, string) VALUES (:id, :name);