]> andersk Git - moira.git/blob - server/qvalidate.pc
5877935ff13a97b09358eb47c5b6bc207fbb2f2f
[moira.git] / server / qvalidate.pc
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
20 EXEC SQL INCLUDE sqlca;
21 EXEC SQL INCLUDE sqlda;
22
23 RCSID("$Header$");
24
25 extern char *whoami, *table_name[], *sqlbuffer[QMAXARGS];
26 extern int dbms_errno, mr_errcode;
27
28 EXEC SQL BEGIN DECLARE SECTION;
29 extern char stmt_buf[];
30 EXEC SQL END DECLARE SECTION;
31
32 int validate_chars(char *argv[], struct valobj *vo);
33 int validate_id(struct query *, char *argv[], struct valobj *vo);
34 int validate_name(char *argv[], struct valobj *vo);
35 int validate_rename(char *argv[], struct valobj *vo);
36 int validate_type(char *argv[], struct valobj *vo);
37 int validate_typedata(struct query *, char *argv[], struct valobj *vo);
38 int validate_len(char *argv[], struct valobj *vo);
39 int validate_num(char *argv[], struct valobj *vo);
40
41 extern SQLDA *sqlald(int, int, int);
42 SQLDA *mr_alloc_sqlda(void);
43
44 EXEC SQL WHENEVER SQLERROR DO dbmserr();
45
46 /* Validation Routines */
47
48 int 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
74 int 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  */
130 static 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
149 int 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   if (!*s)
158     return MR_RESERVED;
159
160   /* check for bad characters */
161   while (*s)
162     {
163       if (illegalchars[(int)*s++])
164         return MR_BAD_CHAR;
165     }
166
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);
172
173   if ((strlen(argv[vo->index]) > len) &&
174       strcmp(argv[vo->index], UNIQUE_LOGIN)) /* kludge... sigh */
175     return MR_ARG_TOO_LONG;
176
177   return MR_EXISTS;
178 }
179
180
181 int validate_id(struct query *q, char *argv[], struct valobj *vo)
182 {
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;
188   char *c;
189
190   name = argv[vo->index];
191   tbl = vo->table;
192   namefield = vo->namefield;
193   idfield = vo->idfield;
194
195   if (tbl == MACHINE_TABLE || tbl == SUBNET_TABLE)
196     {
197       for (c = name; *c; c++)
198         {
199           if (islower(*c))
200             *c = toupper(*c);
201         }
202     }
203   status = name_to_id(name, tbl, &id);
204   if (status == 0)
205     {
206       *(int *)argv[vo->index] = id;
207       return MR_EXISTS;
208     }
209   else if (status == MR_NO_MATCH && tbl == STRINGS_TABLE &&
210            (q->type == APPEND || q->type == UPDATE))
211     {
212       if (strlen(name) >= STRINGS_STRING_SIZE)
213         return MR_ARG_TOO_LONG;
214       id = add_string(name);
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;
222 }
223
224 int validate_name(char *argv[], struct valobj *vo)
225 {
226   char *name, *namefield;
227   char *c;
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         {
235           if (islower(*c))
236             *c = toupper(*c);
237         }
238     }
239   if (!*name)
240     return MR_RESERVED;
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);
244
245   if (dbms_errno)
246     return mr_errcode;
247   return (atoi(sqlbuffer[0]) == 1) ? MR_EXISTS : vo->error;
248 }
249
250 int validate_rename(char *argv[], struct valobj *vo)
251 {
252   EXEC SQL BEGIN DECLARE SECTION;
253   char *name, *namefield, *idfield;
254   int id;
255   EXEC SQL END DECLARE SECTION;
256   int status;
257   char *c;
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     }
272   if (!*name)
273     return MR_RESERVED;
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;
291     }
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;
297 }
298
299
300 int validate_type(char *argv[], struct valobj *vo)
301 {
302   EXEC SQL BEGIN DECLARE SECTION;
303   char *typename;
304   char *val;
305   int cnt;
306   EXEC SQL END DECLARE SECTION;
307   char *c;
308
309   typename = vo->namefield;
310   c = val = argv[vo->index];
311   while (*c)
312     {
313       if (illegalchars[(int)*c++])
314         return MR_BAD_CHAR;
315     }
316
317   /* uppercase type fields */
318   for (c = val; *c; c++)
319     {
320       if (islower(*c))
321         *c = toupper(*c);
322     }
323
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;
329 }
330
331 /* validate member or type-specific data field */
332
333 int validate_typedata(struct query *q, char *argv[], struct valobj *vo)
334 {
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;
342   char *c;
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            */
384           if (vo->idfield && (*(int *)argv[0] == *(int *)argv[vo->index]))
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;
423           if (strlen(name) >= STRINGS_STRING_SIZE)
424             return MR_ARG_TOO_LONG;
425           id = add_string(name);
426         }
427       else if (status)
428         return status;
429     }
430   else if (!strcmp(data_type, "none") || !strcmp(data_type, "all"))
431     id = 0;
432   else
433     return MR_TYPE;
434
435   /* now set value in argv */
436   *(int *)argv[vo->index] = id;
437
438   return MR_EXISTS;
439 }
440
441
442 /* Make sure the data fits in the field */
443 int validate_len(char *argv[], struct valobj *vo)
444 {
445   EXEC SQL BEGIN DECLARE SECTION;
446   int len;
447   char *tname, *cname;
448   EXEC SQL END DECLARE SECTION;
449
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);
454
455   if ((strlen(argv[vo->index]) > len) &&
456       strcmp(argv[vo->index], UNIQUE_LOGIN)) /* kludge... sigh */
457     return MR_ARG_TOO_LONG;
458
459   return MR_EXISTS;
460 }
461
462 /* Make sure the data is numeric */
463 int 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++;
475   if (!*p)
476     return MR_INTEGER;
477
478   for (; *p; p++)
479     {
480       if (*p < '0' || *p > '9')
481         return MR_INTEGER;
482     }
483
484   return MR_EXISTS;
485 }
486
487 /* Check the database at startup time. */
488
489 void sanity_check_database(void)
490 {
491   EXEC SQL BEGIN DECLARE SECTION;
492   int oid, id;
493   EXEC SQL END DECLARE SECTION;
494
495   /* Sometimes a crash can leave strings_id in numvalues in an
496      incorrect state. Check for that and fix it. */
497
498   EXEC SQL SELECT value INTO :oid FROM numvalues WHERE name = 'strings_id';
499
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     }
505
506   if (id != oid + 1)
507     EXEC SQL UPDATE numvalues SET value = :id - 1 WHERE name = 'strings_id';
508 }
509
510
511 char *sqlbuffer[QMAXARGS];
512
513 /* Dynamic SQL support routines */
514 SQLDA *mr_alloc_sqlda(void)
515 {
516   SQLDA *it;
517   int j;
518
519   it = sqlald(QMAXARGS, ARGLEN, 0);
520   if (!it)
521     {
522       com_err(whoami, MR_NO_MEM, "setting up SQLDA");
523       exit(1);
524     }
525
526   for (j = 0; j < QMAXARGS; j++)
527     {
528       it->V[j] = sqlbuffer[j] = xmalloc(ARGLEN);
529       it->T[j] = 97; /* 97 = CHARZ = null-terminated string */
530       it->L[j] = ARGLEN;
531     }
532
533   return it;
534 }
535
536 /*  Adds a string to the string table.  Returns the id number.
537  *
538  */
539 int add_string(char *nm)
540 {
541   EXEC SQL BEGIN DECLARE SECTION;
542   char *name = nm;
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
550   EXEC SQL INSERT INTO strings (string_id, string) VALUES (:id, :name);
551
552   return id;
553 }
This page took 0.065933 seconds and 3 git commands to generate.