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 cache_entry(name, STRINGS_TABLE, id);
213 *(int *)argv[vo->index] = id;
216 else if (status == MR_NO_MATCH || status == MR_NOT_UNIQUE)
222 int validate_name(char *argv[], struct valobj *vo)
224 char *name, *namefield;
227 name = argv[vo->index];
228 namefield = vo->namefield;
229 if (vo->table == SERVERS_TABLE && !strcmp(namefield, "name"))
231 for (c = name; *c; c++)
237 sprintf(stmt_buf, "SELECT DISTINCT COUNT(*) FROM %s WHERE %s.%s = '%s'",
238 table_name[vo->table], table_name[vo->table], namefield, name);
243 return (atoi(sqlbuffer[0]) == 1) ? MR_EXISTS : vo->error;
246 int validate_rename(char *argv[], struct valobj *vo)
248 EXEC SQL BEGIN DECLARE SECTION;
249 char *name, *namefield, *idfield;
251 EXEC SQL END DECLARE SECTION;
255 status = validate_chars(argv, vo);
256 if (status != MR_EXISTS)
258 name = argv[vo->index];
259 /* minor kludge to upcasify machine names */
260 if (vo->table == MACHINE_TABLE)
262 for (c = name; *c; c++)
268 namefield = vo->namefield;
269 idfield = vo->idfield;
273 if (!strcmp(argv[vo->index], argv[vo->index - 1]))
275 sprintf(stmt_buf, "SELECT %s FROM %s WHERE %s = '%s'",
276 namefield, table_name[vo->table], namefield, name);
281 if (sqlca.sqlcode == SQL_NO_MATCH)
282 return MR_EXISTS; /* how's _that_ for intuitive? */
286 status = name_to_id(name, vo->table, &id);
287 if (status == MR_NO_MATCH || id == *(int *)argv[vo->index - 1])
294 int validate_type(char *argv[], struct valobj *vo)
296 EXEC SQL BEGIN DECLARE SECTION;
300 EXEC SQL END DECLARE SECTION;
303 typename = vo->namefield;
304 c = val = argv[vo->index];
307 if (illegalchars[(int)*c++])
311 /* uppercase type fields */
312 for (c = val; *c; c++)
318 EXEC SQL SELECT COUNT(trans) INTO :cnt FROM alias
319 WHERE name = :typename AND type = 'TYPE' AND trans = :val;
322 return cnt ? MR_EXISTS : vo->error;
325 /* validate member or type-specific data field */
327 int validate_typedata(struct query *q, char *argv[], struct valobj *vo)
329 EXEC SQL BEGIN DECLARE SECTION;
334 EXEC SQL END DECLARE SECTION;
338 /* get named object */
339 name = argv[vo->index];
341 /* get field type string (known to be at index-1) */
342 field_type = argv[vo->index - 1];
344 /* get corresponding data type associated with field type name */
345 EXEC SQL SELECT trans INTO :data_type FROM alias
346 WHERE name = :field_type AND type = 'TYPEDATA';
349 if (sqlca.sqlerrd[2] != 1)
352 /* now retrieve the record id corresponding to the named object */
353 if (strchr(data_type, ' '))
354 *strchr(data_type, ' ') = '\0';
355 if (!strcmp(data_type, "user"))
358 if (strchr(name, '@'))
360 status = name_to_id(name, USERS_TABLE, &id);
361 if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
366 else if (!strcmp(data_type, "list"))
369 status = name_to_id(name, LIST_TABLE, &id);
370 if (status && status == MR_NOT_UNIQUE)
372 if (status == MR_NO_MATCH)
374 /* if idfield is non-zero, then if argv[0] matches the string
375 * that we're trying to resolve, we should get the value of
376 * numvalues.[idfield] for the id.
378 if (vo->idfield && !strcmp(argv[0], argv[vo->index]))
380 set_next_object_id(q->validate->object_id, q->rtable, 0);
382 EXEC SQL SELECT value INTO :id FROM numvalues
384 if (sqlca.sqlerrd[2] != 1)
393 else if (!strcmp(data_type, "machine"))
396 for (c = name; *c; c++)
401 status = name_to_id(name, MACHINE_TABLE, &id);
402 if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
407 else if (!strcmp(data_type, "string"))
410 status = name_to_id(name, STRINGS_TABLE, &id);
411 if (status && status == MR_NOT_UNIQUE)
413 if (status == MR_NO_MATCH)
415 if (q->type != APPEND && q->type != UPDATE)
417 if (strlen(name) >= STRINGS_STRING_SIZE)
418 return MR_ARG_TOO_LONG;
419 id = add_string(name);
420 cache_entry(name, STRINGS_TABLE, id);
425 else if (!strcmp(data_type, "none") || !strcmp(data_type, "all"))
430 /* now set value in argv */
431 *(int *)argv[vo->index] = id;
437 /* Make sure the data fits in the field */
438 int validate_len(char *argv[], struct valobj *vo)
440 EXEC SQL BEGIN DECLARE SECTION;
443 EXEC SQL END DECLARE SECTION;
445 tname = table_name[vo->table];
446 cname = vo->namefield;
447 EXEC SQL SELECT data_length INTO :len FROM user_tab_columns
448 WHERE table_name = UPPER(:tname) AND column_name = UPPER(:cname);
450 if ((strlen(argv[vo->index]) > len) &&
451 strcmp(argv[vo->index], UNIQUE_LOGIN)) /* kludge... sigh */
452 return MR_ARG_TOO_LONG;
457 /* Make sure the data is numeric */
458 int validate_num(char *argv[], struct valobj *vo)
460 char *p = argv[vo->index];
462 if (!strcmp(p, UNIQUE_GID) || !strcmp(p, UNIQUE_UID))
475 if (*p < '0' || *p > '9')
482 /* Check the database at startup time. */
484 void sanity_check_database(void)
486 EXEC SQL BEGIN DECLARE SECTION;
488 EXEC SQL END DECLARE SECTION;
490 /* Sometimes a crash can leave strings_id in numvalues in an
491 incorrect state. Check for that and fix it. */
493 EXEC SQL SELECT value INTO :oid FROM numvalues WHERE name = 'strings_id';
495 for (id = oid + 1; sqlca.sqlcode == 0; id++)
497 EXEC SQL SELECT string_id INTO :id FROM strings
498 WHERE string_id = :id;
502 EXEC SQL UPDATE numvalues SET value = :id - 1 WHERE name = 'strings_id';
506 char *sqlbuffer[QMAXARGS];
508 /* Dynamic SQL support routines */
509 SQLDA *mr_alloc_sqlda(void)
514 it = sqlald(QMAXARGS, ARGLEN, 0);
517 com_err(whoami, MR_NO_MEM, "setting up SQLDA");
521 for (j = 0; j < QMAXARGS; j++)
523 it->V[j] = sqlbuffer[j] = xmalloc(ARGLEN);
524 it->T[j] = 97; /* 97 = CHARZ = null-terminated string */
531 /* Adds a string to the string table. Returns the id number.
534 int add_string(char *nm)
536 EXEC SQL BEGIN DECLARE SECTION;
539 EXEC SQL END DECLARE SECTION;
541 EXEC SQL SELECT value INTO :id FROM numvalues WHERE name = 'strings_id';
543 EXEC SQL UPDATE numvalues SET value = :id WHERE name = 'strings_id';
545 EXEC SQL INSERT INTO strings (string_id, string) VALUES (:id, :name);