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