]> andersk Git - moira.git/blame - server/qvalidate.pc
Change MAXLISTDEPTH to 2048.
[moira.git] / server / qvalidate.pc
CommitLineData
7ac48069 1/* $Id$
73cf66ba 2 *
7ac48069 3 * Argument validation routines
73cf66ba 4 *
7ac48069 5 * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology
6 * For copying and distribution information, please see the file
7 * <mit-copyright.h>.
73cf66ba 8 */
9
73cf66ba 10#include <mit-copyright.h>
73cf66ba 11#include "mr_server.h"
03c05291 12#include "query.h"
7ac48069 13#include "qrtn.h"
14
73cf66ba 15#include <ctype.h>
7ac48069 16#include <stdlib.h>
03c05291 17#include <string.h>
7ac48069 18#include <unistd.h>
19
73cf66ba 20EXEC SQL INCLUDE sqlca;
21EXEC SQL INCLUDE sqlda;
7ac48069 22
23RCSID("$Header$");
73cf66ba 24
03c05291 25extern char *whoami, *table_name[], *sqlbuffer[QMAXARGS];
26extern int dbms_errno, mr_errcode;
73cf66ba 27
28EXEC SQL BEGIN DECLARE SECTION;
29extern char stmt_buf[];
30EXEC SQL END DECLARE SECTION;
31
03c05291 32int validate_chars(char *argv[], struct valobj *vo);
33int validate_id(struct query *, char *argv[], struct valobj *vo);
34int validate_name(char *argv[], struct valobj *vo);
35int validate_rename(char *argv[], struct valobj *vo);
36int validate_type(char *argv[], struct valobj *vo);
37int validate_typedata(struct query *, char *argv[], struct valobj *vo);
38int validate_len(char *argv[], struct valobj *vo);
f802fd0d 39int validate_num(char *argv[], struct valobj *vo);
73cf66ba 40
5eaef520 41extern SQLDA *sqlald(int, int, int);
7ac48069 42SQLDA *mr_alloc_sqlda(void);
960b073b 43
03c05291 44EXEC SQL WHENEVER SQLERROR DO dbmserr();
73cf66ba 45
46/* Validation Routines */
47
44d12d58 48int validate_row(struct query *q, char *argv[], struct validate *v)
73cf66ba 49{
5eaef520 50 EXEC SQL BEGIN DECLARE SECTION;
5eaef520 51 int rowcount;
52 EXEC SQL END DECLARE SECTION;
263a36d4 53 char *qual;
5eaef520 54
55 /* build where clause */
263a36d4 56 qual = build_qual(v->qual, v->argc, argv);
5eaef520 57
5eaef520 58 /* look for the record */
59 sprintf(stmt_buf, "SELECT COUNT (*) FROM %s WHERE %s",
60 table_name[q->rtable], qual);
61 dosql(sqlbuffer);
263a36d4 62 free(qual);
5eaef520 63 if (dbms_errno)
64 return mr_errcode;
65
66 rowcount = atoi(sqlbuffer[0]);
67 if (rowcount == 0)
68 return MR_NO_MATCH;
69 if (rowcount > 1)
70 return MR_NOT_UNIQUE;
71 return MR_EXISTS;
73cf66ba 72}
73
44d12d58 74int validate_fields(struct query *q, char *argv[], struct valobj *vo, int n)
73cf66ba 75{
44d12d58 76 int status;
73cf66ba 77
5eaef520 78 while (--n >= 0)
79 {
80 switch (vo->type)
81 {
73cf66ba 82 case V_NAME:
5eaef520 83 status = validate_name(argv, vo);
84 break;
73cf66ba 85
86 case V_ID:
5eaef520 87 status = validate_id(q, argv, vo);
88 break;
73cf66ba 89
90 case V_TYPE:
5eaef520 91 status = validate_type(argv, vo);
92 break;
73cf66ba 93
94 case V_TYPEDATA:
5eaef520 95 status = validate_typedata(q, argv, vo);
96 break;
73cf66ba 97
98 case V_RENAME:
5eaef520 99 status = validate_rename(argv, vo);
100 break;
73cf66ba 101
102 case V_CHAR:
5eaef520 103 status = validate_chars(argv, vo);
104 break;
03c05291 105
106 case V_LEN:
5eaef520 107 status = validate_len(argv, vo);
108 break;
73cf66ba 109
f802fd0d 110 case V_NUM:
111 status = validate_num(argv, vo);
112 break;
73cf66ba 113 }
114
5eaef520 115 if (status != MR_EXISTS)
116 return status;
117 vo++;
73cf66ba 118 }
119
5eaef520 120 if (dbms_errno)
121 return mr_errcode;
122 return MR_SUCCESS;
73cf66ba 123}
124
125
126/* validate_chars: verify that there are no illegal characters in
127 * the string. Legal characters are printing chars other than
128 * ", *, ?, \, [ and ].
129 */
130static int illegalchars[] = {
5eaef520 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,
73cf66ba 147};
148
44d12d58 149int validate_chars(char *argv[], struct valobj *vo)
73cf66ba 150{
5eaef520 151 char *s = argv[vo->index];
5eaef520 152 EXEC SQL BEGIN DECLARE SECTION;
153 int len;
154 char *tname, *cname;
155 EXEC SQL END DECLARE SECTION;
156
157 /* check for bad characters */
158 while (*s)
159 {
7ac48069 160 if (illegalchars[(int)*s++])
5eaef520 161 return MR_BAD_CHAR;
162 }
03c05291 163
5eaef520 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);
03c05291 169
5eaef520 170 if ((strlen(argv[vo->index]) > len) &&
171 strcmp(argv[vo->index], UNIQUE_LOGIN)) /* kludge... sigh */
64798e00 172 return MR_ARG_TOO_LONG;
03c05291 173
5eaef520 174 return MR_EXISTS;
73cf66ba 175}
176
177
44d12d58 178int validate_id(struct query *q, char *argv[], struct valobj *vo)
73cf66ba 179{
5eaef520 180 EXEC SQL BEGIN DECLARE SECTION;
181 char *name, *namefield, *idfield;
182 int id, rowcount, tbl;
183 EXEC SQL END DECLARE SECTION;
184 int status;
44d12d58 185 char *c;
5eaef520 186
187 name = argv[vo->index];
188 tbl = vo->table;
189 namefield = vo->namefield;
190 idfield = vo->idfield;
191
8bf97744 192 if (tbl == MACHINE_TABLE || tbl == SUBNET_TABLE)
5eaef520 193 {
8bf97744 194 for (c = name; *c; c++)
5eaef520 195 {
8bf97744 196 if (islower(*c))
197 *c = toupper(*c);
5eaef520 198 }
5eaef520 199 }
8bf97744 200 status = name_to_id(name, tbl, &id);
201 if (status == 0)
5eaef520 202 {
03c05291 203 *(int *)argv[vo->index] = id;
5eaef520 204 return MR_EXISTS;
73cf66ba 205 }
8bf97744 206 else if (status == MR_NO_MATCH && tbl == STRINGS_TABLE &&
207 (q->type == APPEND || q->type == UPDATE))
208 {
4cad12bc 209 if (strlen(name) >= STRINGS_STRING_SIZE)
210 return MR_ARG_TOO_LONG;
8bf97744 211 id = add_string(name);
212 cache_entry(name, STRINGS_TABLE, id);
213 *(int *)argv[vo->index] = id;
214 return MR_EXISTS;
215 }
216 else if (status == MR_NO_MATCH || status == MR_NOT_UNIQUE)
217 return vo->error;
218 else
219 return status;
73cf66ba 220}
221
44d12d58 222int validate_name(char *argv[], struct valobj *vo)
73cf66ba 223{
5eaef520 224 char *name, *namefield;
44d12d58 225 char *c;
5eaef520 226
227 name = argv[vo->index];
228 namefield = vo->namefield;
229 if (vo->table == SERVERS_TABLE && !strcmp(namefield, "name"))
230 {
231 for (c = name; *c; c++)
232 {
73cf66ba 233 if (islower(*c))
234 *c = toupper(*c);
5eaef520 235 }
73cf66ba 236 }
5eaef520 237 sprintf(stmt_buf, "SELECT DISTINCT COUNT(*) FROM %s WHERE %s.%s = '%s'",
238 table_name[vo->table], table_name[vo->table], namefield, name);
239 dosql(sqlbuffer);
03c05291 240
5eaef520 241 if (dbms_errno)
242 return mr_errcode;
243 return (atoi(sqlbuffer[0]) == 1) ? MR_EXISTS : vo->error;
73cf66ba 244}
245
5eaef520 246int validate_rename(char *argv[], struct valobj *vo)
73cf66ba 247{
5eaef520 248 EXEC SQL BEGIN DECLARE SECTION;
249 char *name, *namefield, *idfield;
250 int id;
251 EXEC SQL END DECLARE SECTION;
252 int status;
44d12d58 253 char *c;
5eaef520 254
255 status = validate_chars(argv, vo);
256 if (status != MR_EXISTS)
257 return status;
258 name = argv[vo->index];
259 /* minor kludge to upcasify machine names */
260 if (vo->table == MACHINE_TABLE)
261 {
262 for (c = name; *c; c++)
263 {
264 if (islower(*c))
265 *c = toupper(*c);
266 }
267 }
268 namefield = vo->namefield;
269 idfield = vo->idfield;
270 id = -1;
271 if (idfield == 0)
272 {
273 if (!strcmp(argv[vo->index], argv[vo->index - 1]))
274 return MR_EXISTS;
275 sprintf(stmt_buf, "SELECT %s FROM %s WHERE %s = '%s'",
276 namefield, table_name[vo->table], namefield, name);
277 dosql(sqlbuffer);
278
279 if (dbms_errno)
280 return mr_errcode;
281 if (sqlca.sqlcode == SQL_NO_MATCH)
282 return MR_EXISTS; /* how's _that_ for intuitive? */
283 else
284 return vo->error;
73cf66ba 285 }
5eaef520 286 status = name_to_id(name, vo->table, &id);
287 if (status == MR_NO_MATCH || id == *(int *)argv[vo->index - 1])
288 return MR_EXISTS;
289 else
290 return vo->error;
73cf66ba 291}
292
293
44d12d58 294int validate_type(char *argv[], struct valobj *vo)
73cf66ba 295{
5eaef520 296 EXEC SQL BEGIN DECLARE SECTION;
297 char *typename;
298 char *val;
299 int cnt;
300 EXEC SQL END DECLARE SECTION;
44d12d58 301 char *c;
5eaef520 302
303 typename = vo->namefield;
304 c = val = argv[vo->index];
305 while (*c)
306 {
7ac48069 307 if (illegalchars[(int)*c++])
5eaef520 308 return MR_BAD_CHAR;
73cf66ba 309 }
310
5eaef520 311 /* uppercase type fields */
312 for (c = val; *c; c++)
313 {
314 if (islower(*c))
315 *c = toupper(*c);
316 }
73cf66ba 317
5eaef520 318 EXEC SQL SELECT COUNT(trans) INTO :cnt FROM alias
319 WHERE name = :typename AND type = 'TYPE' AND trans = :val;
320 if (dbms_errno)
321 return mr_errcode;
322 return cnt ? MR_EXISTS : vo->error;
73cf66ba 323}
324
325/* validate member or type-specific data field */
326
44d12d58 327int validate_typedata(struct query *q, char *argv[], struct valobj *vo)
73cf66ba 328{
5eaef520 329 EXEC SQL BEGIN DECLARE SECTION;
330 char *name;
331 char *field_type;
332 char data_type[129];
333 int id;
334 EXEC SQL END DECLARE SECTION;
335 int status;
44d12d58 336 char *c;
5eaef520 337
338 /* get named object */
339 name = argv[vo->index];
340
341 /* get field type string (known to be at index-1) */
342 field_type = argv[vo->index - 1];
343
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';
347 if (dbms_errno)
348 return mr_errcode;
349 if (sqlca.sqlerrd[2] != 1)
350 return MR_TYPE;
351
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"))
356 {
357 /* USER */
358 if (strchr(name, '@'))
359 return MR_USER;
360 status = name_to_id(name, USERS_TABLE, &id);
361 if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
362 return MR_USER;
363 if (status)
364 return status;
365 }
366 else if (!strcmp(data_type, "list"))
367 {
368 /* LIST */
369 status = name_to_id(name, LIST_TABLE, &id);
370 if (status && status == MR_NOT_UNIQUE)
371 return MR_LIST;
372 if (status == MR_NO_MATCH)
373 {
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.
377 */
a59f007b 378 if (vo->idfield && (*(int *)argv[0] == *(int *)argv[vo->index]))
5eaef520 379 {
380 set_next_object_id(q->validate->object_id, q->rtable, 0);
381 name = vo->idfield;
382 EXEC SQL SELECT value INTO :id FROM numvalues
383 WHERE name = :name;
384 if (sqlca.sqlerrd[2] != 1)
385 return MR_LIST;
386 }
387 else
388 return MR_LIST;
389 }
390 else if (status)
391 return status;
392 }
393 else if (!strcmp(data_type, "machine"))
394 {
395 /* MACHINE */
396 for (c = name; *c; c++)
397 {
398 if (islower(*c))
399 *c = toupper(*c);
400 }
401 status = name_to_id(name, MACHINE_TABLE, &id);
402 if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
403 return MR_MACHINE;
404 if (status)
405 return status;
406 }
407 else if (!strcmp(data_type, "string"))
408 {
409 /* STRING */
410 status = name_to_id(name, STRINGS_TABLE, &id);
411 if (status && status == MR_NOT_UNIQUE)
412 return MR_STRING;
413 if (status == MR_NO_MATCH)
414 {
415 if (q->type != APPEND && q->type != UPDATE)
416 return MR_STRING;
4cad12bc 417 if (strlen(name) >= STRINGS_STRING_SIZE)
418 return MR_ARG_TOO_LONG;
5eaef520 419 id = add_string(name);
420 cache_entry(name, STRINGS_TABLE, id);
421 }
422 else if (status)
423 return status;
73cf66ba 424 }
46b6f1f6 425 else if (!strcmp(data_type, "none") || !strcmp(data_type, "all"))
5eaef520 426 id = 0;
427 else
428 return MR_TYPE;
73cf66ba 429
5eaef520 430 /* now set value in argv */
431 *(int *)argv[vo->index] = id;
73cf66ba 432
5eaef520 433 return MR_EXISTS;
73cf66ba 434}
435
436
03c05291 437/* Make sure the data fits in the field */
44d12d58 438int validate_len(char *argv[], struct valobj *vo)
03c05291 439{
5eaef520 440 EXEC SQL BEGIN DECLARE SECTION;
441 int len;
442 char *tname, *cname;
443 EXEC SQL END DECLARE SECTION;
03c05291 444
5eaef520 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);
03c05291 449
5eaef520 450 if ((strlen(argv[vo->index]) > len) &&
451 strcmp(argv[vo->index], UNIQUE_LOGIN)) /* kludge... sigh */
64798e00 452 return MR_ARG_TOO_LONG;
03c05291 453
5eaef520 454 return MR_EXISTS;
03c05291 455}
456
f802fd0d 457/* Make sure the data is numeric */
458int validate_num(char *argv[], struct valobj *vo)
459{
460 char *p = argv[vo->index];
461
462 if (!strcmp(p, UNIQUE_GID) || !strcmp(p, UNIQUE_UID))
463 {
464 strcpy(p, "-1");
465 return MR_EXISTS;
466 }
467
468 if (*p == '-')
469 p++;
6bd10afd 470 if (!*p)
471 return MR_INTEGER;
472
f802fd0d 473 for (; *p; p++)
474 {
475 if (*p < '0' || *p > '9')
476 return MR_INTEGER;
477 }
478
479 return MR_EXISTS;
480}
481
695afd0d 482/* Check the database at startup time. */
03c05291 483
484void sanity_check_database(void)
485{
5eaef520 486 EXEC SQL BEGIN DECLARE SECTION;
487 int oid, id;
488 EXEC SQL END DECLARE SECTION;
695afd0d 489
5eaef520 490 /* Sometimes a crash can leave strings_id in numvalues in an
491 incorrect state. Check for that and fix it. */
695afd0d 492
5eaef520 493 EXEC SQL SELECT value INTO :oid FROM numvalues WHERE name = 'strings_id';
695afd0d 494
5eaef520 495 for (id = oid + 1; sqlca.sqlcode == 0; id++)
496 {
497 EXEC SQL SELECT string_id INTO :id FROM strings
498 WHERE string_id = :id;
499 }
695afd0d 500
5eaef520 501 if (id != oid + 1)
502 EXEC SQL UPDATE numvalues SET value = :id - 1 WHERE name = 'strings_id';
03c05291 503}
504
505
506char *sqlbuffer[QMAXARGS];
73cf66ba 507
508/* Dynamic SQL support routines */
7ac48069 509SQLDA *mr_alloc_sqlda(void)
73cf66ba 510{
5eaef520 511 SQLDA *it;
44d12d58 512 int j;
5eaef520 513
514 it = sqlald(QMAXARGS, ARGLEN, 0);
515 if (!it)
516 {
517 com_err(whoami, MR_NO_MEM, "setting up SQLDA");
518 exit(1);
73cf66ba 519 }
520
5eaef520 521 for (j = 0; j < QMAXARGS; j++)
522 {
e688520a 523 it->V[j] = sqlbuffer[j] = xmalloc(ARGLEN);
5eaef520 524 it->T[j] = 97; /* 97 = CHARZ = null-terminated string */
525 it->L[j] = ARGLEN;
73cf66ba 526 }
03c05291 527
5eaef520 528 return it;
73cf66ba 529}
530
73cf66ba 531/* Adds a string to the string table. Returns the id number.
5eaef520 532 *
73cf66ba 533 */
5eaef520 534int add_string(char *nm)
73cf66ba 535{
5eaef520 536 EXEC SQL BEGIN DECLARE SECTION;
7ac48069 537 char *name = nm;
5eaef520 538 int id;
539 EXEC SQL END DECLARE SECTION;
540
541 EXEC SQL SELECT value INTO :id FROM numvalues WHERE name = 'strings_id';
542 id++;
543 EXEC SQL UPDATE numvalues SET value = :id WHERE name = 'strings_id';
544
7ac48069 545 EXEC SQL INSERT INTO strings (string_id, string) VALUES (:id, :name);
5eaef520 546
547 return id;
73cf66ba 548}
This page took 0.160494 seconds and 5 git commands to generate.