]> andersk Git - moira.git/blame - server/qvalidate.pc
Support MACHINE members of lists.
[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);
8bf97744 212 *(int *)argv[vo->index] = id;
213 return MR_EXISTS;
214 }
215 else if (status == MR_NO_MATCH || status == MR_NOT_UNIQUE)
216 return vo->error;
217 else
218 return status;
73cf66ba 219}
220
44d12d58 221int validate_name(char *argv[], struct valobj *vo)
73cf66ba 222{
5eaef520 223 char *name, *namefield;
44d12d58 224 char *c;
5eaef520 225
226 name = argv[vo->index];
227 namefield = vo->namefield;
228 if (vo->table == SERVERS_TABLE && !strcmp(namefield, "name"))
229 {
230 for (c = name; *c; c++)
231 {
73cf66ba 232 if (islower(*c))
233 *c = toupper(*c);
5eaef520 234 }
73cf66ba 235 }
5eaef520 236 sprintf(stmt_buf, "SELECT DISTINCT COUNT(*) FROM %s WHERE %s.%s = '%s'",
237 table_name[vo->table], table_name[vo->table], namefield, name);
238 dosql(sqlbuffer);
03c05291 239
5eaef520 240 if (dbms_errno)
241 return mr_errcode;
242 return (atoi(sqlbuffer[0]) == 1) ? MR_EXISTS : vo->error;
73cf66ba 243}
244
5eaef520 245int validate_rename(char *argv[], struct valobj *vo)
73cf66ba 246{
5eaef520 247 EXEC SQL BEGIN DECLARE SECTION;
248 char *name, *namefield, *idfield;
249 int id;
250 EXEC SQL END DECLARE SECTION;
251 int status;
44d12d58 252 char *c;
5eaef520 253
254 status = validate_chars(argv, vo);
255 if (status != MR_EXISTS)
256 return status;
257 name = argv[vo->index];
258 /* minor kludge to upcasify machine names */
259 if (vo->table == MACHINE_TABLE)
260 {
261 for (c = name; *c; c++)
262 {
263 if (islower(*c))
264 *c = toupper(*c);
265 }
266 }
267 namefield = vo->namefield;
268 idfield = vo->idfield;
269 id = -1;
270 if (idfield == 0)
271 {
272 if (!strcmp(argv[vo->index], argv[vo->index - 1]))
273 return MR_EXISTS;
274 sprintf(stmt_buf, "SELECT %s FROM %s WHERE %s = '%s'",
275 namefield, table_name[vo->table], namefield, name);
276 dosql(sqlbuffer);
277
278 if (dbms_errno)
279 return mr_errcode;
280 if (sqlca.sqlcode == SQL_NO_MATCH)
281 return MR_EXISTS; /* how's _that_ for intuitive? */
282 else
283 return vo->error;
73cf66ba 284 }
5eaef520 285 status = name_to_id(name, vo->table, &id);
286 if (status == MR_NO_MATCH || id == *(int *)argv[vo->index - 1])
287 return MR_EXISTS;
288 else
289 return vo->error;
73cf66ba 290}
291
292
44d12d58 293int validate_type(char *argv[], struct valobj *vo)
73cf66ba 294{
5eaef520 295 EXEC SQL BEGIN DECLARE SECTION;
296 char *typename;
297 char *val;
298 int cnt;
299 EXEC SQL END DECLARE SECTION;
44d12d58 300 char *c;
5eaef520 301
302 typename = vo->namefield;
303 c = val = argv[vo->index];
304 while (*c)
305 {
7ac48069 306 if (illegalchars[(int)*c++])
5eaef520 307 return MR_BAD_CHAR;
73cf66ba 308 }
309
5eaef520 310 /* uppercase type fields */
311 for (c = val; *c; c++)
312 {
313 if (islower(*c))
314 *c = toupper(*c);
315 }
73cf66ba 316
5eaef520 317 EXEC SQL SELECT COUNT(trans) INTO :cnt FROM alias
318 WHERE name = :typename AND type = 'TYPE' AND trans = :val;
319 if (dbms_errno)
320 return mr_errcode;
321 return cnt ? MR_EXISTS : vo->error;
73cf66ba 322}
323
324/* validate member or type-specific data field */
325
44d12d58 326int validate_typedata(struct query *q, char *argv[], struct valobj *vo)
73cf66ba 327{
5eaef520 328 EXEC SQL BEGIN DECLARE SECTION;
329 char *name;
330 char *field_type;
331 char data_type[129];
332 int id;
333 EXEC SQL END DECLARE SECTION;
334 int status;
44d12d58 335 char *c;
5eaef520 336
337 /* get named object */
338 name = argv[vo->index];
339
340 /* get field type string (known to be at index-1) */
341 field_type = argv[vo->index - 1];
342
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';
346 if (dbms_errno)
347 return mr_errcode;
348 if (sqlca.sqlerrd[2] != 1)
349 return MR_TYPE;
350
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"))
355 {
356 /* USER */
357 if (strchr(name, '@'))
358 return MR_USER;
359 status = name_to_id(name, USERS_TABLE, &id);
360 if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
361 return MR_USER;
362 if (status)
363 return status;
364 }
365 else if (!strcmp(data_type, "list"))
366 {
367 /* LIST */
368 status = name_to_id(name, LIST_TABLE, &id);
369 if (status && status == MR_NOT_UNIQUE)
370 return MR_LIST;
371 if (status == MR_NO_MATCH)
372 {
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.
376 */
a59f007b 377 if (vo->idfield && (*(int *)argv[0] == *(int *)argv[vo->index]))
5eaef520 378 {
379 set_next_object_id(q->validate->object_id, q->rtable, 0);
380 name = vo->idfield;
381 EXEC SQL SELECT value INTO :id FROM numvalues
382 WHERE name = :name;
383 if (sqlca.sqlerrd[2] != 1)
384 return MR_LIST;
385 }
386 else
387 return MR_LIST;
388 }
389 else if (status)
390 return status;
391 }
392 else if (!strcmp(data_type, "machine"))
393 {
394 /* MACHINE */
395 for (c = name; *c; c++)
396 {
397 if (islower(*c))
398 *c = toupper(*c);
399 }
400 status = name_to_id(name, MACHINE_TABLE, &id);
401 if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
402 return MR_MACHINE;
403 if (status)
404 return status;
405 }
406 else if (!strcmp(data_type, "string"))
407 {
408 /* STRING */
409 status = name_to_id(name, STRINGS_TABLE, &id);
410 if (status && status == MR_NOT_UNIQUE)
411 return MR_STRING;
412 if (status == MR_NO_MATCH)
413 {
414 if (q->type != APPEND && q->type != UPDATE)
415 return MR_STRING;
4cad12bc 416 if (strlen(name) >= STRINGS_STRING_SIZE)
417 return MR_ARG_TOO_LONG;
5eaef520 418 id = add_string(name);
5eaef520 419 }
420 else if (status)
421 return status;
73cf66ba 422 }
46b6f1f6 423 else if (!strcmp(data_type, "none") || !strcmp(data_type, "all"))
5eaef520 424 id = 0;
425 else
426 return MR_TYPE;
73cf66ba 427
5eaef520 428 /* now set value in argv */
429 *(int *)argv[vo->index] = id;
73cf66ba 430
5eaef520 431 return MR_EXISTS;
73cf66ba 432}
433
434
03c05291 435/* Make sure the data fits in the field */
44d12d58 436int validate_len(char *argv[], struct valobj *vo)
03c05291 437{
5eaef520 438 EXEC SQL BEGIN DECLARE SECTION;
439 int len;
440 char *tname, *cname;
441 EXEC SQL END DECLARE SECTION;
03c05291 442
5eaef520 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);
03c05291 447
5eaef520 448 if ((strlen(argv[vo->index]) > len) &&
449 strcmp(argv[vo->index], UNIQUE_LOGIN)) /* kludge... sigh */
64798e00 450 return MR_ARG_TOO_LONG;
03c05291 451
5eaef520 452 return MR_EXISTS;
03c05291 453}
454
f802fd0d 455/* Make sure the data is numeric */
456int validate_num(char *argv[], struct valobj *vo)
457{
458 char *p = argv[vo->index];
459
460 if (!strcmp(p, UNIQUE_GID) || !strcmp(p, UNIQUE_UID))
461 {
462 strcpy(p, "-1");
463 return MR_EXISTS;
464 }
465
466 if (*p == '-')
467 p++;
6bd10afd 468 if (!*p)
469 return MR_INTEGER;
470
f802fd0d 471 for (; *p; p++)
472 {
473 if (*p < '0' || *p > '9')
474 return MR_INTEGER;
475 }
476
477 return MR_EXISTS;
478}
479
695afd0d 480/* Check the database at startup time. */
03c05291 481
482void sanity_check_database(void)
483{
5eaef520 484 EXEC SQL BEGIN DECLARE SECTION;
485 int oid, id;
486 EXEC SQL END DECLARE SECTION;
695afd0d 487
5eaef520 488 /* Sometimes a crash can leave strings_id in numvalues in an
489 incorrect state. Check for that and fix it. */
695afd0d 490
5eaef520 491 EXEC SQL SELECT value INTO :oid FROM numvalues WHERE name = 'strings_id';
695afd0d 492
5eaef520 493 for (id = oid + 1; sqlca.sqlcode == 0; id++)
494 {
495 EXEC SQL SELECT string_id INTO :id FROM strings
496 WHERE string_id = :id;
497 }
695afd0d 498
5eaef520 499 if (id != oid + 1)
500 EXEC SQL UPDATE numvalues SET value = :id - 1 WHERE name = 'strings_id';
03c05291 501}
502
503
504char *sqlbuffer[QMAXARGS];
73cf66ba 505
506/* Dynamic SQL support routines */
7ac48069 507SQLDA *mr_alloc_sqlda(void)
73cf66ba 508{
5eaef520 509 SQLDA *it;
44d12d58 510 int j;
5eaef520 511
512 it = sqlald(QMAXARGS, ARGLEN, 0);
513 if (!it)
514 {
515 com_err(whoami, MR_NO_MEM, "setting up SQLDA");
516 exit(1);
73cf66ba 517 }
518
5eaef520 519 for (j = 0; j < QMAXARGS; j++)
520 {
e688520a 521 it->V[j] = sqlbuffer[j] = xmalloc(ARGLEN);
5eaef520 522 it->T[j] = 97; /* 97 = CHARZ = null-terminated string */
523 it->L[j] = ARGLEN;
73cf66ba 524 }
03c05291 525
5eaef520 526 return it;
73cf66ba 527}
528
73cf66ba 529/* Adds a string to the string table. Returns the id number.
5eaef520 530 *
73cf66ba 531 */
5eaef520 532int add_string(char *nm)
73cf66ba 533{
5eaef520 534 EXEC SQL BEGIN DECLARE SECTION;
7ac48069 535 char *name = nm;
5eaef520 536 int id;
537 EXEC SQL END DECLARE SECTION;
538
539 EXEC SQL SELECT value INTO :id FROM numvalues WHERE name = 'strings_id';
540 id++;
541 EXEC SQL UPDATE numvalues SET value = :id WHERE name = 'strings_id';
542
7ac48069 543 EXEC SQL INSERT INTO strings (string_id, string) VALUES (:id, :name);
5eaef520 544
545 return id;
73cf66ba 546}
This page took 2.298268 seconds and 5 git commands to generate.