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++)
236 sprintf(stmt_buf, "SELECT DISTINCT COUNT(*) FROM %s WHERE %s.%s = '%s'",
237 table_name[vo->table], table_name[vo->table], namefield, name);
242 return (atoi(sqlbuffer[0]) == 1) ? MR_EXISTS : vo->error;
245 int validate_rename(char *argv[], struct valobj *vo)
247 EXEC SQL BEGIN DECLARE SECTION;
248 char *name, *namefield, *idfield;
250 EXEC SQL END DECLARE SECTION;
254 status = validate_chars(argv, vo);
255 if (status != MR_EXISTS)
257 name = argv[vo->index];
258 /* minor kludge to upcasify machine names */
259 if (vo->table == MACHINE_TABLE)
261 for (c = name; *c; c++)
267 namefield = vo->namefield;
268 idfield = vo->idfield;
272 if (!strcmp(argv[vo->index], argv[vo->index - 1]))
274 sprintf(stmt_buf, "SELECT %s FROM %s WHERE %s = '%s'",
275 namefield, table_name[vo->table], namefield, name);
280 if (sqlca.sqlcode == SQL_NO_MATCH)
281 return MR_EXISTS; /* how's _that_ for intuitive? */
285 status = name_to_id(name, vo->table, &id);
286 if (status == MR_NO_MATCH || id == *(int *)argv[vo->index - 1])
293 int validate_type(char *argv[], struct valobj *vo)
295 EXEC SQL BEGIN DECLARE SECTION;
299 EXEC SQL END DECLARE SECTION;
302 typename = vo->namefield;
303 c = val = argv[vo->index];
306 if (illegalchars[(int)*c++])
310 /* uppercase type fields */
311 for (c = val; *c; c++)
317 EXEC SQL SELECT COUNT(trans) INTO :cnt FROM alias
318 WHERE name = :typename AND type = 'TYPE' AND trans = :val;
321 return cnt ? MR_EXISTS : vo->error;
324 /* validate member or type-specific data field */
326 int validate_typedata(struct query *q, char *argv[], struct valobj *vo)
328 EXEC SQL BEGIN DECLARE SECTION;
333 EXEC SQL END DECLARE SECTION;
337 /* get named object */
338 name = argv[vo->index];
340 /* get field type string (known to be at index-1) */
341 field_type = argv[vo->index - 1];
343 /* get corresponding data type associated with field type name */
344 EXEC SQL SELECT trans INTO :data_type FROM alias
345 WHERE name = :field_type AND type = 'TYPEDATA';
348 if (sqlca.sqlerrd[2] != 1)
351 /* now retrieve the record id corresponding to the named object */
352 if (strchr(data_type, ' '))
353 *strchr(data_type, ' ') = '\0';
354 if (!strcmp(data_type, "user"))
357 if (strchr(name, '@'))
359 status = name_to_id(name, USERS_TABLE, &id);
360 if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
365 else if (!strcmp(data_type, "list"))
368 status = name_to_id(name, LIST_TABLE, &id);
369 if (status && status == MR_NOT_UNIQUE)
371 if (status == MR_NO_MATCH)
373 /* if idfield is non-zero, then if argv[0] matches the string
374 * that we're trying to resolve, we should get the value of
375 * numvalues.[idfield] for the id.
377 if (vo->idfield && (*(int *)argv[0] == *(int *)argv[vo->index]))
379 set_next_object_id(q->validate->object_id, q->rtable, 0);
381 EXEC SQL SELECT value INTO :id FROM numvalues
383 if (sqlca.sqlerrd[2] != 1)
392 else if (!strcmp(data_type, "machine"))
395 for (c = name; *c; c++)
400 status = name_to_id(name, MACHINE_TABLE, &id);
401 if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
406 else if (!strcmp(data_type, "string"))
409 status = name_to_id(name, STRINGS_TABLE, &id);
410 if (status && status == MR_NOT_UNIQUE)
412 if (status == MR_NO_MATCH)
414 if (q->type != APPEND && q->type != UPDATE)
416 if (strlen(name) >= STRINGS_STRING_SIZE)
417 return MR_ARG_TOO_LONG;
418 id = add_string(name);
423 else if (!strcmp(data_type, "none") || !strcmp(data_type, "all"))
428 /* now set value in argv */
429 *(int *)argv[vo->index] = id;
435 /* Make sure the data fits in the field */
436 int validate_len(char *argv[], struct valobj *vo)
438 EXEC SQL BEGIN DECLARE SECTION;
441 EXEC SQL END DECLARE SECTION;
443 tname = table_name[vo->table];
444 cname = vo->namefield;
445 EXEC SQL SELECT data_length INTO :len FROM user_tab_columns
446 WHERE table_name = UPPER(:tname) AND column_name = UPPER(:cname);
448 if ((strlen(argv[vo->index]) > len) &&
449 strcmp(argv[vo->index], UNIQUE_LOGIN)) /* kludge... sigh */
450 return MR_ARG_TOO_LONG;
455 /* Make sure the data is numeric */
456 int validate_num(char *argv[], struct valobj *vo)
458 char *p = argv[vo->index];
460 if (!strcmp(p, UNIQUE_GID) || !strcmp(p, UNIQUE_UID))
473 if (*p < '0' || *p > '9')
480 /* Check the database at startup time. */
482 void sanity_check_database(void)
484 EXEC SQL BEGIN DECLARE SECTION;
486 EXEC SQL END DECLARE SECTION;
488 /* Sometimes a crash can leave strings_id in numvalues in an
489 incorrect state. Check for that and fix it. */
491 EXEC SQL SELECT value INTO :oid FROM numvalues WHERE name = 'strings_id';
493 for (id = oid + 1; sqlca.sqlcode == 0; id++)
495 EXEC SQL SELECT string_id INTO :id FROM strings
496 WHERE string_id = :id;
500 EXEC SQL UPDATE numvalues SET value = :id - 1 WHERE name = 'strings_id';
504 char *sqlbuffer[QMAXARGS];
506 /* Dynamic SQL support routines */
507 SQLDA *mr_alloc_sqlda(void)
512 it = sqlald(QMAXARGS, ARGLEN, 0);
515 com_err(whoami, MR_NO_MEM, "setting up SQLDA");
519 for (j = 0; j < QMAXARGS; j++)
521 it->V[j] = sqlbuffer[j] = xmalloc(ARGLEN);
522 it->T[j] = 97; /* 97 = CHARZ = null-terminated string */
529 /* Adds a string to the string table. Returns the id number.
532 int add_string(char *nm)
534 EXEC SQL BEGIN DECLARE SECTION;
537 EXEC SQL END DECLARE SECTION;
539 EXEC SQL SELECT value INTO :id FROM numvalues WHERE name = 'strings_id';
541 EXEC SQL UPDATE numvalues SET value = :id WHERE name = 'strings_id';
543 EXEC SQL INSERT INTO strings (string_id, string) VALUES (:id, :name);