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