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