]> andersk Git - moira.git/blame - server/qvalidate.pc
remove the (unused) table locking code
[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);
03c05291 40int convert_wildcards_uppercase(char *arg);
73cf66ba 41
5eaef520 42extern SQLDA *sqlald(int, int, int);
7ac48069 43SQLDA *mr_alloc_sqlda(void);
960b073b 44
03c05291 45EXEC SQL WHENEVER SQLERROR DO dbmserr();
73cf66ba 46
47/* Validation Routines */
48
44d12d58 49int validate_row(struct query *q, char *argv[], struct validate *v)
73cf66ba 50{
5eaef520 51 EXEC SQL BEGIN DECLARE SECTION;
52 char qual[128];
53 int rowcount;
54 EXEC SQL END DECLARE SECTION;
55
56 /* build where clause */
57 build_qual(v->qual, v->argc, argv, qual);
58
5eaef520 59 /* look for the record */
60 sprintf(stmt_buf, "SELECT COUNT (*) FROM %s WHERE %s",
61 table_name[q->rtable], qual);
62 dosql(sqlbuffer);
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;
113
03c05291 114 case V_WILD:
5eaef520 115 status = convert_wildcards(argv[vo->index]);
116 break;
73cf66ba 117
118 case V_UPWILD:
5eaef520 119 status = convert_wildcards_uppercase(argv[vo->index]);
120 break;
73cf66ba 121
122 }
123
5eaef520 124 if (status != MR_EXISTS)
125 return status;
126 vo++;
73cf66ba 127 }
128
5eaef520 129 if (dbms_errno)
130 return mr_errcode;
131 return MR_SUCCESS;
73cf66ba 132}
133
134
135/* validate_chars: verify that there are no illegal characters in
136 * the string. Legal characters are printing chars other than
137 * ", *, ?, \, [ and ].
138 */
139static int illegalchars[] = {
5eaef520 140 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
141 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
142 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
143 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0 - ? */
144 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* : - O */
145 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, /* P - _ */
146 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
147 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
148 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
149 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
150 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
151 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
152 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
153 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
154 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
155 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
73cf66ba 156};
157
44d12d58 158int validate_chars(char *argv[], struct valobj *vo)
73cf66ba 159{
5eaef520 160 char *s = argv[vo->index];
5eaef520 161 EXEC SQL BEGIN DECLARE SECTION;
162 int len;
163 char *tname, *cname;
164 EXEC SQL END DECLARE SECTION;
165
166 /* check for bad characters */
167 while (*s)
168 {
7ac48069 169 if (illegalchars[(int)*s++])
5eaef520 170 return MR_BAD_CHAR;
171 }
03c05291 172
5eaef520 173 /* check for length */
174 tname = table_name[vo->table];
175 cname = vo->namefield;
176 EXEC SQL SELECT data_length INTO :len FROM user_tab_columns
177 WHERE table_name = UPPER(:tname) AND column_name = UPPER(:cname);
03c05291 178
5eaef520 179 if ((strlen(argv[vo->index]) > len) &&
180 strcmp(argv[vo->index], UNIQUE_LOGIN)) /* kludge... sigh */
64798e00 181 return MR_ARG_TOO_LONG;
03c05291 182
5eaef520 183 return MR_EXISTS;
73cf66ba 184}
185
186
44d12d58 187int validate_id(struct query *q, char *argv[], struct valobj *vo)
73cf66ba 188{
5eaef520 189 EXEC SQL BEGIN DECLARE SECTION;
190 char *name, *namefield, *idfield;
191 int id, rowcount, tbl;
192 EXEC SQL END DECLARE SECTION;
193 int status;
44d12d58 194 char *c;
5eaef520 195
196 name = argv[vo->index];
197 tbl = vo->table;
198 namefield = vo->namefield;
199 idfield = vo->idfield;
200
201 if ((tbl == USERS_TABLE && !strcmp(namefield, "login")) ||
202 tbl == MACHINE_TABLE || tbl == SUBNET_TABLE || tbl == FILESYS_TABLE ||
e688520a 203 tbl == LIST_TABLE || tbl == CLUSTERS_TABLE || tbl == STRINGS_TABLE)
5eaef520 204 {
205 if (tbl == MACHINE_TABLE || tbl == SUBNET_TABLE)
206 {
207 for (c = name; *c; c++)
208 {
209 if (islower(*c))
210 *c = toupper(*c);
211 }
212 }
03c05291 213 status = name_to_id(name, tbl, &id);
5eaef520 214 if (status == 0)
215 {
216 *(int *)argv[vo->index] = id;
217 return MR_EXISTS;
218 }
219 else if (status == MR_NO_MATCH && tbl == STRINGS_TABLE &&
220 (q->type == APPEND || q->type == UPDATE))
221 {
222 id = add_string(name);
223 cache_entry(name, STRINGS_TABLE, id);
224 *(int *)argv[vo->index] = id;
225 return MR_EXISTS;
226 }
227 else if (status == MR_NO_MATCH || status == MR_NOT_UNIQUE)
228 return vo->error;
03c05291 229 else
5eaef520 230 return status;
231 }
232 else
233 {
03c05291 234 /* else, it's `dubu', which uses unix_uid from users */
235 EXEC SQL SELECT COUNT(*) INTO :rowcount FROM users
236 WHERE unix_uid = :name;
5eaef520 237 if (dbms_errno)
238 return mr_errcode;
239 if (rowcount != 1)
240 return vo->error;
03c05291 241 EXEC SQL SELECT users_id INTO :id FROM users
242 WHERE unix_uid = :name;
243 *(int *)argv[vo->index] = id;
5eaef520 244 return MR_EXISTS;
73cf66ba 245 }
73cf66ba 246}
247
44d12d58 248int validate_name(char *argv[], struct valobj *vo)
73cf66ba 249{
5eaef520 250 char *name, *namefield;
44d12d58 251 char *c;
5eaef520 252
253 name = argv[vo->index];
254 namefield = vo->namefield;
255 if (vo->table == SERVERS_TABLE && !strcmp(namefield, "name"))
256 {
257 for (c = name; *c; c++)
258 {
73cf66ba 259 if (islower(*c))
260 *c = toupper(*c);
5eaef520 261 }
73cf66ba 262 }
5eaef520 263 sprintf(stmt_buf, "SELECT DISTINCT COUNT(*) FROM %s WHERE %s.%s = '%s'",
264 table_name[vo->table], table_name[vo->table], namefield, name);
265 dosql(sqlbuffer);
03c05291 266
5eaef520 267 if (dbms_errno)
268 return mr_errcode;
269 return (atoi(sqlbuffer[0]) == 1) ? MR_EXISTS : vo->error;
73cf66ba 270}
271
5eaef520 272int validate_rename(char *argv[], struct valobj *vo)
73cf66ba 273{
5eaef520 274 EXEC SQL BEGIN DECLARE SECTION;
275 char *name, *namefield, *idfield;
276 int id;
277 EXEC SQL END DECLARE SECTION;
278 int status;
44d12d58 279 char *c;
5eaef520 280
281 status = validate_chars(argv, vo);
282 if (status != MR_EXISTS)
283 return status;
284 name = argv[vo->index];
285 /* minor kludge to upcasify machine names */
286 if (vo->table == MACHINE_TABLE)
287 {
288 for (c = name; *c; c++)
289 {
290 if (islower(*c))
291 *c = toupper(*c);
292 }
293 }
294 namefield = vo->namefield;
295 idfield = vo->idfield;
296 id = -1;
297 if (idfield == 0)
298 {
299 if (!strcmp(argv[vo->index], argv[vo->index - 1]))
300 return MR_EXISTS;
301 sprintf(stmt_buf, "SELECT %s FROM %s WHERE %s = '%s'",
302 namefield, table_name[vo->table], namefield, name);
303 dosql(sqlbuffer);
304
305 if (dbms_errno)
306 return mr_errcode;
307 if (sqlca.sqlcode == SQL_NO_MATCH)
308 return MR_EXISTS; /* how's _that_ for intuitive? */
309 else
310 return vo->error;
73cf66ba 311 }
5eaef520 312 status = name_to_id(name, vo->table, &id);
313 if (status == MR_NO_MATCH || id == *(int *)argv[vo->index - 1])
314 return MR_EXISTS;
315 else
316 return vo->error;
73cf66ba 317}
318
319
44d12d58 320int validate_type(char *argv[], struct valobj *vo)
73cf66ba 321{
5eaef520 322 EXEC SQL BEGIN DECLARE SECTION;
323 char *typename;
324 char *val;
325 int cnt;
326 EXEC SQL END DECLARE SECTION;
44d12d58 327 char *c;
5eaef520 328
329 typename = vo->namefield;
330 c = val = argv[vo->index];
331 while (*c)
332 {
7ac48069 333 if (illegalchars[(int)*c++])
5eaef520 334 return MR_BAD_CHAR;
73cf66ba 335 }
336
5eaef520 337 /* uppercase type fields */
338 for (c = val; *c; c++)
339 {
340 if (islower(*c))
341 *c = toupper(*c);
342 }
73cf66ba 343
5eaef520 344 EXEC SQL SELECT COUNT(trans) INTO :cnt FROM alias
345 WHERE name = :typename AND type = 'TYPE' AND trans = :val;
346 if (dbms_errno)
347 return mr_errcode;
348 return cnt ? MR_EXISTS : vo->error;
73cf66ba 349}
350
351/* validate member or type-specific data field */
352
44d12d58 353int validate_typedata(struct query *q, char *argv[], struct valobj *vo)
73cf66ba 354{
5eaef520 355 EXEC SQL BEGIN DECLARE SECTION;
356 char *name;
357 char *field_type;
358 char data_type[129];
359 int id;
360 EXEC SQL END DECLARE SECTION;
361 int status;
44d12d58 362 char *c;
5eaef520 363
364 /* get named object */
365 name = argv[vo->index];
366
367 /* get field type string (known to be at index-1) */
368 field_type = argv[vo->index - 1];
369
370 /* get corresponding data type associated with field type name */
371 EXEC SQL SELECT trans INTO :data_type FROM alias
372 WHERE name = :field_type AND type = 'TYPEDATA';
373 if (dbms_errno)
374 return mr_errcode;
375 if (sqlca.sqlerrd[2] != 1)
376 return MR_TYPE;
377
378 /* now retrieve the record id corresponding to the named object */
379 if (strchr(data_type, ' '))
380 *strchr(data_type, ' ') = '\0';
381 if (!strcmp(data_type, "user"))
382 {
383 /* USER */
384 if (strchr(name, '@'))
385 return MR_USER;
386 status = name_to_id(name, USERS_TABLE, &id);
387 if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
388 return MR_USER;
389 if (status)
390 return status;
391 }
392 else if (!strcmp(data_type, "list"))
393 {
394 /* LIST */
395 status = name_to_id(name, LIST_TABLE, &id);
396 if (status && status == MR_NOT_UNIQUE)
397 return MR_LIST;
398 if (status == MR_NO_MATCH)
399 {
400 /* if idfield is non-zero, then if argv[0] matches the string
401 * that we're trying to resolve, we should get the value of
402 * numvalues.[idfield] for the id.
403 */
404 if (vo->idfield && !strcmp(argv[0], argv[vo->index]))
405 {
406 set_next_object_id(q->validate->object_id, q->rtable, 0);
407 name = vo->idfield;
408 EXEC SQL SELECT value INTO :id FROM numvalues
409 WHERE name = :name;
410 if (sqlca.sqlerrd[2] != 1)
411 return MR_LIST;
412 }
413 else
414 return MR_LIST;
415 }
416 else if (status)
417 return status;
418 }
419 else if (!strcmp(data_type, "machine"))
420 {
421 /* MACHINE */
422 for (c = name; *c; c++)
423 {
424 if (islower(*c))
425 *c = toupper(*c);
426 }
427 status = name_to_id(name, MACHINE_TABLE, &id);
428 if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
429 return MR_MACHINE;
430 if (status)
431 return status;
432 }
433 else if (!strcmp(data_type, "string"))
434 {
435 /* STRING */
436 status = name_to_id(name, STRINGS_TABLE, &id);
437 if (status && status == MR_NOT_UNIQUE)
438 return MR_STRING;
439 if (status == MR_NO_MATCH)
440 {
441 if (q->type != APPEND && q->type != UPDATE)
442 return MR_STRING;
443 id = add_string(name);
444 cache_entry(name, STRINGS_TABLE, id);
445 }
446 else if (status)
447 return status;
73cf66ba 448 }
5eaef520 449 else if (!strcmp(data_type, "none"))
450 id = 0;
451 else
452 return MR_TYPE;
73cf66ba 453
5eaef520 454 /* now set value in argv */
455 *(int *)argv[vo->index] = id;
73cf66ba 456
5eaef520 457 return MR_EXISTS;
73cf66ba 458}
459
460
03c05291 461/* Make sure the data fits in the field */
44d12d58 462int validate_len(char *argv[], struct valobj *vo)
03c05291 463{
5eaef520 464 EXEC SQL BEGIN DECLARE SECTION;
465 int len;
466 char *tname, *cname;
467 EXEC SQL END DECLARE SECTION;
03c05291 468
5eaef520 469 tname = table_name[vo->table];
470 cname = vo->namefield;
471 EXEC SQL SELECT data_length INTO :len FROM user_tab_columns
472 WHERE table_name = UPPER(:tname) AND column_name = UPPER(:cname);
03c05291 473
5eaef520 474 if ((strlen(argv[vo->index]) > len) &&
475 strcmp(argv[vo->index], UNIQUE_LOGIN)) /* kludge... sigh */
64798e00 476 return MR_ARG_TOO_LONG;
03c05291 477
5eaef520 478 return MR_EXISTS;
03c05291 479}
480
f802fd0d 481/* Make sure the data is numeric */
482int validate_num(char *argv[], struct valobj *vo)
483{
484 char *p = argv[vo->index];
485
486 if (!strcmp(p, UNIQUE_GID) || !strcmp(p, UNIQUE_UID))
487 {
488 strcpy(p, "-1");
489 return MR_EXISTS;
490 }
491
492 if (*p == '-')
493 p++;
494 for (; *p; p++)
495 {
496 if (*p < '0' || *p > '9')
497 return MR_INTEGER;
498 }
499
500 return MR_EXISTS;
501}
502
695afd0d 503/* Check the database at startup time. */
03c05291 504
505void sanity_check_database(void)
506{
5eaef520 507 EXEC SQL BEGIN DECLARE SECTION;
508 int oid, id;
509 EXEC SQL END DECLARE SECTION;
695afd0d 510
5eaef520 511 /* Sometimes a crash can leave strings_id in numvalues in an
512 incorrect state. Check for that and fix it. */
695afd0d 513
5eaef520 514 EXEC SQL SELECT value INTO :oid FROM numvalues WHERE name = 'strings_id';
695afd0d 515
5eaef520 516 for (id = oid + 1; sqlca.sqlcode == 0; id++)
517 {
518 EXEC SQL SELECT string_id INTO :id FROM strings
519 WHERE string_id = :id;
520 }
695afd0d 521
5eaef520 522 if (id != oid + 1)
523 EXEC SQL UPDATE numvalues SET value = :id - 1 WHERE name = 'strings_id';
03c05291 524}
525
526
527char *sqlbuffer[QMAXARGS];
73cf66ba 528
529/* Dynamic SQL support routines */
7ac48069 530SQLDA *mr_alloc_sqlda(void)
73cf66ba 531{
5eaef520 532 SQLDA *it;
44d12d58 533 int j;
5eaef520 534
535 it = sqlald(QMAXARGS, ARGLEN, 0);
536 if (!it)
537 {
538 com_err(whoami, MR_NO_MEM, "setting up SQLDA");
539 exit(1);
73cf66ba 540 }
541
5eaef520 542 for (j = 0; j < QMAXARGS; j++)
543 {
e688520a 544 it->V[j] = sqlbuffer[j] = xmalloc(ARGLEN);
5eaef520 545 it->T[j] = 97; /* 97 = CHARZ = null-terminated string */
546 it->L[j] = ARGLEN;
73cf66ba 547 }
03c05291 548
5eaef520 549 return it;
73cf66ba 550}
551
552
73cf66ba 553/* Convert normal Unix-style wildcards to SQL voodoo */
5eaef520 554int convert_wildcards(char *arg)
73cf66ba 555{
5eaef520 556 static char buffer[ARGLEN];
44d12d58 557 char *s, *d;
5eaef520 558
559 for (d = buffer, s = arg; *s; s++)
560 {
561 switch (*s)
562 {
563 case '*':
564 *d++ = '%';
565 *d++ = '%';
566 break;
567 case '?':
568 *d++ = '_';
569 break;
570 case '_':
571 *d++ = '*';
572 *d++ = *s;
573 break;
574 case '%':
575 *d++ = '*';
576 *d++ = '%';
577 *d++ = '%';
578 break;
579 default:
580 *d++ = *s;
581 break;
73cf66ba 582 }
583 }
5eaef520 584 *d = '\0';
73cf66ba 585
5eaef520 586 /* Copy back into argv */
587 strcpy(arg, buffer);
73cf66ba 588
5eaef520 589 return MR_EXISTS;
73cf66ba 590}
591
592/* This version includes uppercase conversion, for things like gmac.
593 * This is necessary because "LIKE" doesn't work with "uppercase()".
594 * Including it in a wildcard routine saves making two passes over
595 * the argument string.
596 */
5eaef520 597int convert_wildcards_uppercase(char *arg)
73cf66ba 598{
5eaef520 599 static char buffer[ARGLEN];
44d12d58 600 char *s, *d;
5eaef520 601
602 for (d = buffer, s = arg; *s; s++)
603 {
604 switch (*s)
605 {
606 case '*':
607 *d++ = '%';
608 *d++ = '%';
609 break;
610 case '?':
611 *d++ = '_';
612 break;
613 case '_':
614 *d++ = '*';
615 *d++ = *s;
616 break;
617 case '%':
618 *d++ = '*';
619 *d++ = '%';
620 *d++ = '%';
621 break;
622 default:
623 *d++ = toupper(*s); /* This is the only diff. */
624 break;
73cf66ba 625 }
626 }
5eaef520 627 *d = '\0';
73cf66ba 628
5eaef520 629 /* Copy back into argv */
630 strcpy(arg, buffer);
73cf66ba 631
5eaef520 632 return MR_EXISTS;
73cf66ba 633}
634
635
73cf66ba 636/* Adds a string to the string table. Returns the id number.
5eaef520 637 *
73cf66ba 638 */
5eaef520 639int add_string(char *nm)
73cf66ba 640{
5eaef520 641 EXEC SQL BEGIN DECLARE SECTION;
7ac48069 642 char *name = nm;
5eaef520 643 int id;
644 EXEC SQL END DECLARE SECTION;
645
646 EXEC SQL SELECT value INTO :id FROM numvalues WHERE name = 'strings_id';
647 id++;
648 EXEC SQL UPDATE numvalues SET value = :id WHERE name = 'strings_id';
649
7ac48069 650 EXEC SQL INSERT INTO strings (string_id, string) VALUES (:id, :name);
5eaef520 651
652 return id;
73cf66ba 653}
This page took 0.189771 seconds and 5 git commands to generate.