]> andersk Git - moira.git/blame_incremental - server/qvalidate.pc
Allow hostname to start with a digit in hostname_check, but disallow it
[moira.git] / server / qvalidate.pc
... / ...
CommitLineData
1/* $Id$
2 *
3 * Argument validation routines
4 *
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>.
8 */
9
10#include <mit-copyright.h>
11#include "mr_server.h"
12#include "query.h"
13#include "qrtn.h"
14
15#include <ctype.h>
16#include <stdlib.h>
17#include <string.h>
18#include <unistd.h>
19
20EXEC SQL INCLUDE sqlca;
21EXEC SQL INCLUDE sqlda;
22
23RCSID("$Header$");
24
25extern char *whoami, *table_name[], *sqlbuffer[QMAXARGS];
26extern int dbms_errno, mr_errcode;
27
28EXEC SQL BEGIN DECLARE SECTION;
29extern char stmt_buf[];
30EXEC SQL END DECLARE SECTION;
31
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);
39int validate_num(char *argv[], struct valobj *vo);
40
41extern SQLDA *sqlald(int, int, int);
42SQLDA *mr_alloc_sqlda(void);
43
44EXEC SQL WHENEVER SQLERROR DO dbmserr();
45
46/* Validation Routines */
47
48int validate_row(struct query *q, char *argv[], struct validate *v)
49{
50 EXEC SQL BEGIN DECLARE SECTION;
51 int rowcount;
52 EXEC SQL END DECLARE SECTION;
53 char *qual;
54
55 /* build where clause */
56 qual = build_qual(v->qual, v->argc, argv);
57
58 /* look for the record */
59 sprintf(stmt_buf, "SELECT COUNT (*) FROM %s WHERE %s",
60 table_name[q->rtable], qual);
61 dosql(sqlbuffer);
62 free(qual);
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;
72}
73
74int validate_fields(struct query *q, char *argv[], struct valobj *vo, int n)
75{
76 int status;
77
78 while (--n >= 0)
79 {
80 switch (vo->type)
81 {
82 case V_NAME:
83 status = validate_name(argv, vo);
84 break;
85
86 case V_ID:
87 status = validate_id(q, argv, vo);
88 break;
89
90 case V_TYPE:
91 status = validate_type(argv, vo);
92 break;
93
94 case V_TYPEDATA:
95 status = validate_typedata(q, argv, vo);
96 break;
97
98 case V_RENAME:
99 status = validate_rename(argv, vo);
100 break;
101
102 case V_CHAR:
103 status = validate_chars(argv, vo);
104 break;
105
106 case V_LEN:
107 status = validate_len(argv, vo);
108 break;
109
110 case V_NUM:
111 status = validate_num(argv, vo);
112 break;
113 }
114
115 if (status != MR_EXISTS)
116 return status;
117 vo++;
118 }
119
120 if (dbms_errno)
121 return mr_errcode;
122 return MR_SUCCESS;
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[] = {
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,
147};
148
149int validate_chars(char *argv[], struct valobj *vo)
150{
151 char *s = argv[vo->index];
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 {
160 if (illegalchars[(int)*s++])
161 return MR_BAD_CHAR;
162 }
163
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);
169
170 if ((strlen(argv[vo->index]) > len) &&
171 strcmp(argv[vo->index], UNIQUE_LOGIN)) /* kludge... sigh */
172 return MR_ARG_TOO_LONG;
173
174 return MR_EXISTS;
175}
176
177
178int validate_id(struct query *q, char *argv[], struct valobj *vo)
179{
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;
185 char *c;
186
187 name = argv[vo->index];
188 tbl = vo->table;
189 namefield = vo->namefield;
190 idfield = vo->idfield;
191
192 if (tbl == MACHINE_TABLE || tbl == SUBNET_TABLE)
193 {
194 for (c = name; *c; c++)
195 {
196 if (islower(*c))
197 *c = toupper(*c);
198 }
199 }
200 status = name_to_id(name, tbl, &id);
201 if (status == 0)
202 {
203 *(int *)argv[vo->index] = id;
204 return MR_EXISTS;
205 }
206 else if (status == MR_NO_MATCH && tbl == STRINGS_TABLE &&
207 (q->type == APPEND || q->type == UPDATE))
208 {
209 if (strlen(name) >= STRINGS_STRING_SIZE)
210 return MR_ARG_TOO_LONG;
211 id = add_string(name);
212 cache_entry(name, STRINGS_TABLE, id);
213 *(int *)argv[vo->index] = id;
214 return MR_EXISTS;
215 }
216 else if (status == MR_NO_MATCH || status == MR_NOT_UNIQUE)
217 return vo->error;
218 else
219 return status;
220}
221
222int validate_name(char *argv[], struct valobj *vo)
223{
224 char *name, *namefield;
225 char *c;
226
227 name = argv[vo->index];
228 namefield = vo->namefield;
229 if (vo->table == SERVERS_TABLE && !strcmp(namefield, "name"))
230 {
231 for (c = name; *c; c++)
232 {
233 if (islower(*c))
234 *c = toupper(*c);
235 }
236 }
237 sprintf(stmt_buf, "SELECT DISTINCT COUNT(*) FROM %s WHERE %s.%s = '%s'",
238 table_name[vo->table], table_name[vo->table], namefield, name);
239 dosql(sqlbuffer);
240
241 if (dbms_errno)
242 return mr_errcode;
243 return (atoi(sqlbuffer[0]) == 1) ? MR_EXISTS : vo->error;
244}
245
246int validate_rename(char *argv[], struct valobj *vo)
247{
248 EXEC SQL BEGIN DECLARE SECTION;
249 char *name, *namefield, *idfield;
250 int id;
251 EXEC SQL END DECLARE SECTION;
252 int status;
253 char *c;
254
255 status = validate_chars(argv, vo);
256 if (status != MR_EXISTS)
257 return status;
258 name = argv[vo->index];
259 /* minor kludge to upcasify machine names */
260 if (vo->table == MACHINE_TABLE)
261 {
262 for (c = name; *c; c++)
263 {
264 if (islower(*c))
265 *c = toupper(*c);
266 }
267 }
268 namefield = vo->namefield;
269 idfield = vo->idfield;
270 id = -1;
271 if (idfield == 0)
272 {
273 if (!strcmp(argv[vo->index], argv[vo->index - 1]))
274 return MR_EXISTS;
275 sprintf(stmt_buf, "SELECT %s FROM %s WHERE %s = '%s'",
276 namefield, table_name[vo->table], namefield, name);
277 dosql(sqlbuffer);
278
279 if (dbms_errno)
280 return mr_errcode;
281 if (sqlca.sqlcode == SQL_NO_MATCH)
282 return MR_EXISTS; /* how's _that_ for intuitive? */
283 else
284 return vo->error;
285 }
286 status = name_to_id(name, vo->table, &id);
287 if (status == MR_NO_MATCH || id == *(int *)argv[vo->index - 1])
288 return MR_EXISTS;
289 else
290 return vo->error;
291}
292
293
294int validate_type(char *argv[], struct valobj *vo)
295{
296 EXEC SQL BEGIN DECLARE SECTION;
297 char *typename;
298 char *val;
299 int cnt;
300 EXEC SQL END DECLARE SECTION;
301 char *c;
302
303 typename = vo->namefield;
304 c = val = argv[vo->index];
305 while (*c)
306 {
307 if (illegalchars[(int)*c++])
308 return MR_BAD_CHAR;
309 }
310
311 /* uppercase type fields */
312 for (c = val; *c; c++)
313 {
314 if (islower(*c))
315 *c = toupper(*c);
316 }
317
318 EXEC SQL SELECT COUNT(trans) INTO :cnt FROM alias
319 WHERE name = :typename AND type = 'TYPE' AND trans = :val;
320 if (dbms_errno)
321 return mr_errcode;
322 return cnt ? MR_EXISTS : vo->error;
323}
324
325/* validate member or type-specific data field */
326
327int validate_typedata(struct query *q, char *argv[], struct valobj *vo)
328{
329 EXEC SQL BEGIN DECLARE SECTION;
330 char *name;
331 char *field_type;
332 char data_type[129];
333 int id;
334 EXEC SQL END DECLARE SECTION;
335 int status;
336 char *c;
337
338 /* get named object */
339 name = argv[vo->index];
340
341 /* get field type string (known to be at index-1) */
342 field_type = argv[vo->index - 1];
343
344 /* get corresponding data type associated with field type name */
345 EXEC SQL SELECT trans INTO :data_type FROM alias
346 WHERE name = :field_type AND type = 'TYPEDATA';
347 if (dbms_errno)
348 return mr_errcode;
349 if (sqlca.sqlerrd[2] != 1)
350 return MR_TYPE;
351
352 /* now retrieve the record id corresponding to the named object */
353 if (strchr(data_type, ' '))
354 *strchr(data_type, ' ') = '\0';
355 if (!strcmp(data_type, "user"))
356 {
357 /* USER */
358 if (strchr(name, '@'))
359 return MR_USER;
360 status = name_to_id(name, USERS_TABLE, &id);
361 if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
362 return MR_USER;
363 if (status)
364 return status;
365 }
366 else if (!strcmp(data_type, "list"))
367 {
368 /* LIST */
369 status = name_to_id(name, LIST_TABLE, &id);
370 if (status && status == MR_NOT_UNIQUE)
371 return MR_LIST;
372 if (status == MR_NO_MATCH)
373 {
374 /* if idfield is non-zero, then if argv[0] matches the string
375 * that we're trying to resolve, we should get the value of
376 * numvalues.[idfield] for the id.
377 */
378 if (vo->idfield && !strcmp(argv[0], argv[vo->index]))
379 {
380 set_next_object_id(q->validate->object_id, q->rtable, 0);
381 name = vo->idfield;
382 EXEC SQL SELECT value INTO :id FROM numvalues
383 WHERE name = :name;
384 if (sqlca.sqlerrd[2] != 1)
385 return MR_LIST;
386 }
387 else
388 return MR_LIST;
389 }
390 else if (status)
391 return status;
392 }
393 else if (!strcmp(data_type, "machine"))
394 {
395 /* MACHINE */
396 for (c = name; *c; c++)
397 {
398 if (islower(*c))
399 *c = toupper(*c);
400 }
401 status = name_to_id(name, MACHINE_TABLE, &id);
402 if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
403 return MR_MACHINE;
404 if (status)
405 return status;
406 }
407 else if (!strcmp(data_type, "string"))
408 {
409 /* STRING */
410 status = name_to_id(name, STRINGS_TABLE, &id);
411 if (status && status == MR_NOT_UNIQUE)
412 return MR_STRING;
413 if (status == MR_NO_MATCH)
414 {
415 if (q->type != APPEND && q->type != UPDATE)
416 return MR_STRING;
417 if (strlen(name) >= STRINGS_STRING_SIZE)
418 return MR_ARG_TOO_LONG;
419 id = add_string(name);
420 cache_entry(name, STRINGS_TABLE, id);
421 }
422 else if (status)
423 return status;
424 }
425 else if (!strcmp(data_type, "none"))
426 id = 0;
427 else
428 return MR_TYPE;
429
430 /* now set value in argv */
431 *(int *)argv[vo->index] = id;
432
433 return MR_EXISTS;
434}
435
436
437/* Make sure the data fits in the field */
438int validate_len(char *argv[], struct valobj *vo)
439{
440 EXEC SQL BEGIN DECLARE SECTION;
441 int len;
442 char *tname, *cname;
443 EXEC SQL END DECLARE SECTION;
444
445 tname = table_name[vo->table];
446 cname = vo->namefield;
447 EXEC SQL SELECT data_length INTO :len FROM user_tab_columns
448 WHERE table_name = UPPER(:tname) AND column_name = UPPER(:cname);
449
450 if ((strlen(argv[vo->index]) > len) &&
451 strcmp(argv[vo->index], UNIQUE_LOGIN)) /* kludge... sigh */
452 return MR_ARG_TOO_LONG;
453
454 return MR_EXISTS;
455}
456
457/* Make sure the data is numeric */
458int validate_num(char *argv[], struct valobj *vo)
459{
460 char *p = argv[vo->index];
461
462 if (!strcmp(p, UNIQUE_GID) || !strcmp(p, UNIQUE_UID))
463 {
464 strcpy(p, "-1");
465 return MR_EXISTS;
466 }
467
468 if (*p == '-')
469 p++;
470 if (!*p)
471 return MR_INTEGER;
472
473 for (; *p; p++)
474 {
475 if (*p < '0' || *p > '9')
476 return MR_INTEGER;
477 }
478
479 return MR_EXISTS;
480}
481
482/* Check the database at startup time. */
483
484void sanity_check_database(void)
485{
486 EXEC SQL BEGIN DECLARE SECTION;
487 int oid, id;
488 EXEC SQL END DECLARE SECTION;
489
490 /* Sometimes a crash can leave strings_id in numvalues in an
491 incorrect state. Check for that and fix it. */
492
493 EXEC SQL SELECT value INTO :oid FROM numvalues WHERE name = 'strings_id';
494
495 for (id = oid + 1; sqlca.sqlcode == 0; id++)
496 {
497 EXEC SQL SELECT string_id INTO :id FROM strings
498 WHERE string_id = :id;
499 }
500
501 if (id != oid + 1)
502 EXEC SQL UPDATE numvalues SET value = :id - 1 WHERE name = 'strings_id';
503}
504
505
506char *sqlbuffer[QMAXARGS];
507
508/* Dynamic SQL support routines */
509SQLDA *mr_alloc_sqlda(void)
510{
511 SQLDA *it;
512 int j;
513
514 it = sqlald(QMAXARGS, ARGLEN, 0);
515 if (!it)
516 {
517 com_err(whoami, MR_NO_MEM, "setting up SQLDA");
518 exit(1);
519 }
520
521 for (j = 0; j < QMAXARGS; j++)
522 {
523 it->V[j] = sqlbuffer[j] = xmalloc(ARGLEN);
524 it->T[j] = 97; /* 97 = CHARZ = null-terminated string */
525 it->L[j] = ARGLEN;
526 }
527
528 return it;
529}
530
531/* Adds a string to the string table. Returns the id number.
532 *
533 */
534int add_string(char *nm)
535{
536 EXEC SQL BEGIN DECLARE SECTION;
537 char *name = nm;
538 int id;
539 EXEC SQL END DECLARE SECTION;
540
541 EXEC SQL SELECT value INTO :id FROM numvalues WHERE name = 'strings_id';
542 id++;
543 EXEC SQL UPDATE numvalues SET value = :id WHERE name = 'strings_id';
544
545 EXEC SQL INSERT INTO strings (string_id, string) VALUES (:id, :name);
546
547 return id;
548}
This page took 0.121022 seconds and 5 git commands to generate.