]> andersk Git - moira.git/blob - server/qvalidate.pc
Do proper validation of sids to ensure row doesn't already exist.
[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   /* 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
178 int 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
222 int 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
246 int 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
294 int 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
327 int 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 && (*(int *)argv[0] == *(int *)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") || !strcmp(data_type, "all"))
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 */
438 int 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 */
458 int 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
484 void 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
506 char *sqlbuffer[QMAXARGS];
507
508 /* Dynamic SQL support routines */
509 SQLDA *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  */
534 int 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.077273 seconds and 5 git commands to generate.