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