]> andersk Git - moira.git/blob - server/qvalidate.pc
f40f19a868a988af876612f51da03bcf4032cb7d
[moira.git] / server / qvalidate.pc
1 /*
2  *      $Source$
3  *      $Author$
4  *      $Header$
5  *
6  *      Copyright (C) 1987 by the Massachusetts Institute of Technology
7  *      For copying and distribution information, please see the file
8  *      <mit-copyright.h>.
9  *
10  */
11
12 #ifndef lint
13 static char *rcsid_qsupport_dc = "$Header$";
14 #endif lint
15
16 #include <mit-copyright.h>
17 #include <unistd.h>
18 #include "mr_server.h"
19 #include "query.h"
20 #include <ctype.h>
21 #include <string.h>
22 EXEC SQL INCLUDE sqlca;
23 EXEC SQL INCLUDE sqlda;
24 #include "qrtn.h"
25
26 extern char *whoami, *table_name[], *sqlbuffer[QMAXARGS];
27 extern int dbms_errno, mr_errcode;
28
29 EXEC SQL BEGIN DECLARE SECTION;
30 extern char stmt_buf[];
31 EXEC SQL END DECLARE SECTION;
32
33 int validate_chars(char *argv[], struct valobj *vo);
34 int validate_id(struct query *, char *argv[], struct valobj *vo);
35 int validate_name(char *argv[], struct valobj *vo);
36 int validate_rename(char *argv[], struct valobj *vo);
37 int validate_type(char *argv[], struct valobj *vo);
38 int validate_typedata(struct query *, char *argv[], struct valobj *vo);
39 int validate_len(char *argv[], struct valobj *vo);
40 int validate_num(char *argv[], struct valobj *vo);
41 int convert_wildcards_uppercase(char *arg);
42
43 extern SQLDA *sqlald(int,int,int);
44
45 EXEC SQL WHENEVER SQLERROR DO dbmserr();
46
47 /* Validation Routines */
48
49 int validate_row(q, argv, v)
50     register struct query *q;
51     char *argv[];
52     register struct validate *v;
53 {
54     EXEC SQL BEGIN DECLARE SECTION;
55     char qual[128];
56     int rowcount;
57     EXEC SQL END DECLARE SECTION;
58
59     /* build where clause */
60     build_qual(v->qual, v->argc, argv, qual);
61
62     if (log_flags & LOG_VALID)
63         /* tell the logfile what we're doing */
64         com_err(whoami, 0, "validating row: %s", qual);
65
66     /* look for the record */
67     sprintf(stmt_buf,"SELECT COUNT (*) FROM %s WHERE %s",
68             table_name[q->rtable],qual);
69     dosql(sqlbuffer);
70     if (dbms_errno) return(mr_errcode);
71
72     rowcount = atoi(sqlbuffer[0]);
73     if (rowcount == 0) return(MR_NO_MATCH);
74     if (rowcount > 1) return(MR_NOT_UNIQUE);
75     return(MR_EXISTS);
76 }
77
78 int validate_fields(q, argv, vo, n)
79     struct query *q;
80     register char *argv[];
81     register struct valobj *vo;
82     register int n;
83 {
84     register int status;
85
86     while (--n >= 0) {
87         switch (vo->type) {
88         case V_NAME:
89             if (log_flags & LOG_VALID)
90                 com_err(whoami, 0, "validating %s in %s: %s",
91                     vo->namefield, table_name[vo->table], argv[vo->index]);
92             status = validate_name(argv, vo);
93             break;
94
95         case V_ID:
96             if (log_flags & LOG_VALID)
97                 com_err(whoami, 0, "validating %s in %s: %s",
98                     vo->idfield, table_name[vo->table], argv[vo->index]);
99             status = validate_id(q, argv, vo);
100             break;
101
102         case V_TYPE:
103             if (log_flags & LOG_VALID)
104                 com_err(whoami, 0, "validating %s type: %s",
105                     table_name[vo->table], argv[vo->index]);
106             status = validate_type(argv, vo);
107             break;
108
109         case V_TYPEDATA:
110             if (log_flags & LOG_VALID)
111                 com_err(whoami, 0, "validating typed data (%s): %s",
112                     argv[vo->index - 1], argv[vo->index]);
113             status = validate_typedata(q, argv, vo);
114             break;
115
116         case V_RENAME:
117             if (log_flags & LOG_VALID)
118                 com_err(whoami, 0, "validating rename %s in %s",
119                         argv[vo->index], table_name[vo->table]);
120             status = validate_rename(argv, vo);
121             break;
122
123         case V_CHAR:
124             if (log_flags & LOG_VALID)
125               com_err(whoami, 0, "validating chars: %s", argv[vo->index]);
126             status = validate_chars(argv, vo);
127             break;
128
129         case V_LEN:
130             if (log_flags & LOG_VALID)
131               com_err(whoami, 0, "validating length: %s", argv[vo->index]);
132             status = validate_len(argv, vo);
133             break;
134
135         case V_NUM:
136             if (log_flags & LOG_VALID)
137               com_err(whoami, 0, "validating number: %s", argv[vo->index]);
138             status = validate_num(argv, vo);
139             break;
140
141         case V_WILD:
142             status = convert_wildcards(argv[vo->index]);
143             break;
144
145         case V_UPWILD:
146             status = convert_wildcards_uppercase(argv[vo->index]);
147             break;
148
149         }
150
151         if (status != MR_EXISTS) return(status);
152         vo++;
153     }
154
155     if (dbms_errno) return(mr_errcode);
156     return(MR_SUCCESS);
157 }
158
159
160 /* validate_chars: verify that there are no illegal characters in
161  * the string.  Legal characters are printing chars other than
162  * ", *, ?, \, [ and ].
163  */
164 static int illegalchars[] = {
165     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
166     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
167     0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
168     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0 - ? */
169     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* : - O */
170     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, /* P - _ */
171     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
172     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
173     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
174     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
175     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
176     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
177     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
178     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
179     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
180     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
181 };
182
183 int validate_chars(argv, vo)
184     char *argv[];
185     register struct valobj *vo;
186 {
187     char *s=argv[vo->index];
188     int arg;
189     EXEC SQL BEGIN DECLARE SECTION;
190     int len;
191     char *tname, *cname;
192     EXEC SQL END DECLARE SECTION;
193
194
195     /* check for bad characters */
196     while (*s)
197       if (illegalchars[*s++])
198         return(MR_BAD_CHAR);
199
200     /* check for length */
201     tname = table_name[vo->table];
202     cname = vo->namefield;
203     EXEC SQL SELECT data_length INTO :len FROM user_tab_columns
204       WHERE table_name=UPPER(:tname) AND column_name=UPPER(:cname);
205
206     if((strlen(argv[vo->index]) > len) &&
207        strcmp(argv[vo->index], UNIQUE_LOGIN)) /* kludge... sigh */
208       argv[vo->index][len]='\0'; /* truncate */
209
210     return MR_EXISTS;
211 }
212
213
214 int validate_id(q, argv, vo)
215     struct query *q;
216     char *argv[];
217     register struct valobj *vo;
218 {
219     EXEC SQL BEGIN DECLARE SECTION;
220     char *name, *namefield, *idfield;
221     int id, rowcount, tbl;
222     EXEC SQL END DECLARE SECTION;
223     int status;
224     register char *c;
225
226     name = argv[vo->index];
227     tbl = vo->table;
228     namefield = vo->namefield;
229     idfield = vo->idfield;
230
231     if ((tbl==USERS_TABLE && !strcmp(namefield, "login")) ||
232         tbl==MACHINE_TABLE || tbl==SUBNET_TABLE || tbl==FILESYS_TABLE ||
233         tbl==LIST_TABLE || tbl==CLUSTER_TABLE || tbl==STRINGS_TABLE) {
234       if (tbl==MACHINE_TABLE || tbl==SUBNET_TABLE)
235         for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
236       status = name_to_id(name, tbl, &id);
237       if (status == 0) {
238         *(int *)argv[vo->index] = id;
239         return(MR_EXISTS);
240       } else if (status == MR_NO_MATCH && tbl==STRINGS_TABLE &&
241                  (q->type == APPEND || q->type == UPDATE)) {
242         id=add_string(name);
243         cache_entry(name, STRINGS_TABLE, id);
244         *(int *)argv[vo->index] = id;
245         return(MR_EXISTS);
246       } else if (status == MR_NO_MATCH || status == MR_NOT_UNIQUE)
247         return(vo->error);
248       else
249         return(status);
250     } else {
251       /* else, it's `dubu', which uses unix_uid from users */
252       EXEC SQL SELECT COUNT(*) INTO :rowcount FROM users
253         WHERE unix_uid = :name;
254       if (dbms_errno) return(mr_errcode);
255       if (rowcount != 1) return(vo->error);
256       EXEC SQL SELECT users_id INTO :id FROM users
257         WHERE unix_uid = :name;
258       *(int *)argv[vo->index] = id;
259       return(MR_EXISTS);
260     }
261 }
262
263 int validate_name(argv, vo)
264     char *argv[];
265     register struct valobj *vo;
266 {
267     char *name, *namefield;
268     register char *c;
269
270     name = argv[vo->index];
271     namefield = vo->namefield;
272     if (vo->table==SERVERS_TABLE && !strcmp(namefield, "name")) {
273         for (c = name; *c; c++)
274           if (islower(*c))
275             *c = toupper(*c);
276     }
277     sprintf(stmt_buf,"SELECT DISTINCT COUNT(*) FROM %s WHERE %s.%s = '%s'",
278             table_name[vo->table],table_name[vo->table],namefield,name);
279     dosql(sqlbuffer);
280
281     if (dbms_errno) return(mr_errcode);
282     return ((atoi(sqlbuffer[0]) == 1) ? MR_EXISTS : vo->error);
283 }
284
285 int validate_rename(argv, vo)
286      char *argv[];
287      struct valobj *vo;
288 {
289     EXEC SQL BEGIN DECLARE SECTION;
290     char *name, *namefield, *idfield;
291     int id;
292     EXEC SQL END DECLARE SECTION;
293     int status;
294     register char *c;
295
296     status = validate_chars(argv, vo);
297     if(status != MR_EXISTS) return status;
298     name=argv[vo->index];
299     /* minor kludge to upcasify machine names */
300     if (vo->table == MACHINE_TABLE)
301         for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
302     namefield = vo->namefield;
303     idfield = vo->idfield;
304     id = -1;
305     if (idfield == 0) {
306         if (!strcmp(argv[vo->index], argv[vo->index - 1]))
307           return(MR_EXISTS);
308         sprintf(stmt_buf,"SELECT %s FROM %s WHERE %s = '%s'",
309                 namefield,table_name[vo->table],namefield,name);
310         dosql(sqlbuffer);
311
312         if (dbms_errno) return(mr_errcode);
313         if (sqlca.sqlcode==SQL_NO_MATCH)
314           return(MR_EXISTS); /* how's _that_ for intuitive? */
315         else
316           return(vo->error);
317     }
318     status = name_to_id(name, vo->table, &id);
319     if (status == MR_NO_MATCH || id == *(int *)argv[vo->index - 1])
320       return(MR_EXISTS);
321     else
322       return(vo->error);
323 }
324
325
326 int validate_type(argv, vo)
327     char *argv[];
328     register struct valobj *vo;
329 {
330     EXEC SQL BEGIN DECLARE SECTION;
331     char *typename;
332     char *val;
333     int cnt;
334     EXEC SQL END DECLARE SECTION;
335     register char *c;
336
337     typename = vo->namefield;
338     c = val = argv[vo->index];
339     while (*c) {
340         if (illegalchars[*c++])
341           return(MR_BAD_CHAR);
342     }
343
344     /* uppercase type fields */
345     for (c = val; *c; c++) if (islower(*c)) *c = toupper(*c);
346
347     EXEC SQL SELECT COUNT(trans) INTO :cnt FROM alias
348       WHERE name = :typename AND type='TYPE' AND trans = :val;
349     if (dbms_errno) return(mr_errcode);
350     return (cnt ? MR_EXISTS : vo->error);
351 }
352
353 /* validate member or type-specific data field */
354
355 int validate_typedata(q, argv, vo)
356     register struct query *q;
357     register char *argv[];
358     register struct valobj *vo;
359 {
360     EXEC SQL BEGIN DECLARE SECTION;
361     char *name;
362     char *field_type;
363     char data_type[129];
364     int id;
365     EXEC SQL END DECLARE SECTION;
366     int status;
367     register char *c;
368
369     /* get named object */
370     name = argv[vo->index];
371
372     /* get field type string (known to be at index-1) */
373     field_type = argv[vo->index-1];
374
375     /* get corresponding data type associated with field type name */
376     EXEC SQL SELECT trans INTO :data_type FROM alias
377       WHERE name = :field_type AND type='TYPEDATA';
378     if (dbms_errno) return(mr_errcode);
379     if (sqlca.sqlerrd[2] != 1) return(MR_TYPE);
380
381     /* now retrieve the record id corresponding to the named object */
382     if (strchr(data_type, ' '))
383         *strchr(data_type, ' ') = 0;
384     if (!strcmp(data_type, "user")) {
385         /* USER */
386         if (strchr(name, '@'))
387           return(MR_USER);
388         status = name_to_id(name, USERS_TABLE, &id);
389         if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
390           return(MR_USER);
391         if (status) return(status);
392     } else if (!strcmp(data_type, "list")) {
393         /* LIST */
394         status = name_to_id(name, LIST_TABLE, &id);
395         if (status && status == MR_NOT_UNIQUE)
396           return(MR_LIST);
397         if (status == MR_NO_MATCH) {
398             /* if idfield is non-zero, then if argv[0] matches the string
399              * that we're trying to resolve, we should get the value of
400              * numvalues.[idfield] for the id.
401              */
402             if (vo->idfield && !strcmp(argv[0], argv[vo->index])) {
403                 set_next_object_id(q->validate->object_id, q->rtable, 0);
404                 name = vo->idfield;
405                 EXEC SQL SELECT value INTO :id FROM numvalues
406                   WHERE name = :name;
407                 if (sqlca.sqlerrd[2] != 1) return(MR_LIST);
408             } else
409               return(MR_LIST);
410         } else if (status) return(status);
411     } else if (!strcmp(data_type, "machine")) {
412         /* MACHINE */
413         for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
414         status = name_to_id(name, MACHINE_TABLE, &id);
415         if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
416           return(MR_MACHINE);
417         if (status) return(status);
418     } else if (!strcmp(data_type, "string")) {
419         /* STRING */
420         status = name_to_id(name, STRINGS_TABLE, &id);
421         if (status && status == MR_NOT_UNIQUE)
422           return(MR_STRING);
423         if (status == MR_NO_MATCH) {
424             if (q->type != APPEND && q->type != UPDATE) return(MR_STRING);
425             id=add_string(name);
426             cache_entry(name, STRINGS_TABLE, id);
427         } else if (status) return(status);
428     } else if (!strcmp(data_type, "none")) {
429         id = 0;
430     } else {
431         return(MR_TYPE);
432     }
433
434     /* now set value in argv */
435     *(int *)argv[vo->index] = id;
436
437     return (MR_EXISTS);
438 }
439
440
441 /* Make sure the data fits in the field */
442 int validate_len(argv, vo)
443     register char *argv[];
444     register struct valobj *vo;
445 {
446     EXEC SQL BEGIN DECLARE SECTION;
447     int len;
448     char *tname, *cname;
449     EXEC SQL END DECLARE SECTION;
450
451     tname = table_name[vo->table];
452     cname = vo->namefield;
453     EXEC SQL SELECT data_length INTO :len FROM user_tab_columns
454       WHERE table_name=UPPER(:tname) AND column_name=UPPER(:cname);
455
456     if((strlen(argv[vo->index]) > len) &&
457        strcmp(argv[vo->index], UNIQUE_LOGIN)) /* kludge... sigh */
458       argv[vo->index][len]='\0'; /* truncate */
459
460     return MR_EXISTS;
461 }
462
463 /* Make sure the data is numeric */
464 int validate_num(argv, vo)
465     register char *argv[];
466     register struct valobj *vo;
467 {
468     char *p = argv[vo->index];
469     
470     if (*p == '-') p++;
471     for (;*p;p++)
472         if (*p < '0' || *p > '9') return MR_INTEGER;
473     
474     return MR_EXISTS;
475 }
476
477 /* Check the database at startup time. */
478
479 void sanity_check_database(void)
480 {
481     EXEC SQL BEGIN DECLARE SECTION;
482     int oid, id;
483     EXEC SQL END DECLARE SECTION;
484
485     /* Sometimes a crash can leave strings_id in numvalues in an
486        incorrect state. Check for that and fix it. */
487
488     EXEC SQL SELECT value INTO :oid FROM numvalues WHERE name='strings_id';
489
490     for (id=oid+1; sqlca.sqlcode==0; id++)
491         EXEC SQL SELECT string_id INTO :id FROM strings
492             WHERE string_id=:id;
493
494     if (id!=oid+1)
495         EXEC SQL UPDATE numvalues SET value=:id-1 WHERE name='strings_id';
496 }
497
498
499 char *sqlbuffer[QMAXARGS];
500
501 /* Dynamic SQL support routines */
502 SQLDA *mr_alloc_sqlda()
503 {
504     SQLDA *it;
505     register int j;
506
507     it=sqlald(QMAXARGS, ARGLEN, 0);
508     if(it==NULL) {
509         com_err(whoami, MR_NO_MEM, "setting up SQLDA");
510         exit(1);
511     }
512
513     for(j=0; j<QMAXARGS; j++) {
514         it->V[j]=sqlbuffer[j]=malloc(ARGLEN);
515         it->T[j]=97; /* 97 = CHARZ = null-terminated string */
516         it->L[j]=ARGLEN;
517     }
518
519     return it;
520 }
521
522
523 /* Convert normal Unix-style wildcards to SQL voodoo */
524 int convert_wildcards(arg)
525     char *arg;
526 {
527     static char buffer[ARGLEN];
528     register char *s, *d;
529
530     for(d=buffer,s=arg;*s;s++) {
531         switch(*s) {
532           case '*': *d++='%'; *d++='%'; break;
533           case '?': *d++='_'; break;
534           case '_': *d++='*'; *d++ = *s; break;
535           case '%': *d++='*'; *d++='%'; *d++='%'; break;
536           default: *d++ = *s; break;
537         }
538     }
539     *d='\0';
540
541     /* Copy back into argv */
542     strcpy(arg,buffer);
543
544     return(MR_EXISTS);
545 }
546
547 /* This version includes uppercase conversion, for things like gmac.
548  * This is necessary because "LIKE" doesn't work with "uppercase()".
549  * Including it in a wildcard routine saves making two passes over
550  * the argument string.
551  */
552 int convert_wildcards_uppercase(arg)
553     char *arg;
554 {
555     static char buffer[ARGLEN];
556     register char *s, *d;
557
558     for(d=buffer,s=arg;*s;s++) {
559         switch(*s) {
560           case '*': *d++='%'; *d++='%'; break;
561           case '?': *d++='_'; break;
562           case '_': *d++='*'; *d++ = *s; break;
563           case '%': *d++='*'; *d++='%'; *d++='%'; break;
564           default: *d++=toupper(*s); break;       /* This is the only diff. */
565         }
566     }
567     *d='\0';
568
569     /* Copy back into argv */
570     strcpy(arg,buffer);
571
572     return(MR_EXISTS);
573 }
574
575
576 /*  Adds a string to the string table.  Returns the id number.
577  * 
578  */
579 int add_string(name)
580     EXEC SQL BEGIN DECLARE SECTION; 
581     char *name;
582     EXEC SQL END DECLARE SECTION;
583 {
584     EXEC SQL BEGIN DECLARE SECTION;
585     char buf[256];
586     int id;
587     EXEC SQL END DECLARE SECTION; 
588
589     EXEC SQL SELECT value INTO :id FROM numvalues WHERE name = 'strings_id';
590     id++;
591     EXEC SQL UPDATE numvalues SET value = :id WHERE name = 'strings_id';
592     
593     EXEC SQL INSERT INTO strings (string_id, string) VALUES (:id, :name);
594  
595     return(id);
596 }
This page took 0.130993 seconds and 3 git commands to generate.