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