]> andersk Git - moira.git/blob - server/qsetup.pc
fix case-insensitive name check so names don't conflict with
[moira.git] / server / qsetup.pc
1 /* $Id$
2  *
3  * Query setup 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 <arpa/inet.h>
16 #include <netinet/in.h>
17
18 #include <ctype.h>
19 #include <stdlib.h>
20 #include <string.h>
21
22 EXEC SQL INCLUDE sqlca;
23
24 RCSID("$Header$");
25
26 extern char *whoami;
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 EXEC SQL WHENEVER SQLERROR DO dbmserr();
34
35 int hostname_check(char *name);
36 int hostinfo_check(char *name, int num);
37 int prefetch_value(struct query *q, char **argv, client *cl);
38 int check_nfs(int mach_idx, char *name, char *access);
39
40 /* Setup Routines */
41
42 /* Setup routine for add_user
43  *
44  * Inputs: argv[0] - login
45  *         argv[1] - uid
46  *
47  * Description:
48  *
49  * - if argv[1] == UNIQUE_UID then set argv[1] = next(uid)
50  * - if argv[0] == UNIQUE_LOGIN then set argv[0] = "#<uid>"
51  */
52
53 int setup_ausr(struct query *q, char *argv[], client *cl)
54 {
55   int row, err;
56   EXEC SQL BEGIN DECLARE SECTION;
57   int nuid;
58   EXEC SQL END DECLARE SECTION;
59
60   if (!strcmp(q->shortname, "uusr") || !strcmp(q->shortname, "uuac"))
61     row = 2;
62   else
63     row = 1;
64
65   if (strlen(argv[row + 2]) + strlen(argv[row + 3]) +
66       strlen(argv[row + 4]) + 2 > USERS_FULLNAME_SIZE)
67     return MR_ARG_TOO_LONG;
68
69   if (!strcmp(argv[row], UNIQUE_UID) || atoi(argv[row]) == -1)
70     {
71       if ((err = set_next_object_id("unix_uid", USERS_TABLE, 1)))
72         return err;
73       EXEC SQL SELECT value INTO :nuid FROM numvalues WHERE name = 'unix_uid';
74       if (sqlca.sqlerrd[2] != 1)
75         return MR_INTERNAL;
76       sprintf(argv[row], "%d", nuid);
77     }
78
79   if (!strcmp(argv[0], UNIQUE_LOGIN) || atoi(argv[row]) == -1)
80     sprintf(argv[0], "#%s", argv[row]);
81
82   if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
83     return mr_errcode;
84
85   return MR_SUCCESS;
86 }
87
88
89 /* setup_dusr - verify that the user is no longer being referenced
90  * and may safely be deleted.
91  */
92
93 int setup_dusr(struct query *q, char *argv[], client *cl)
94 {
95   EXEC SQL BEGIN DECLARE SECTION;
96   int flag, id, cnt;
97   EXEC SQL END DECLARE SECTION;
98
99   id = *(int *)argv[0];
100
101   /* For now, only allow users to be deleted if their status is 0 */
102   EXEC SQL SELECT status INTO :flag FROM users WHERE users_id = :id;
103   if (flag != 0 && flag != 4)
104     return MR_IN_USE;
105
106   EXEC SQL DELETE FROM quota WHERE entity_id = :id AND type = 'USER';
107   EXEC SQL DELETE FROM krbmap WHERE users_id = :id;
108   EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
109     WHERE member_id = :id AND member_type = 'USER';
110   if (cnt > 0)
111     return MR_IN_USE;
112   EXEC SQL SELECT COUNT(label) INTO :cnt FROM filesys
113     WHERE owner = :id;
114   if (cnt > 0)
115     return MR_IN_USE;
116   EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
117     WHERE acl_id = :id AND acl_type = 'USER';
118   if (cnt > 0)
119     return MR_IN_USE;
120   EXEC SQL SELECT COUNT(name) INTO :cnt FROM servers
121     WHERE acl_id = :id AND acl_type = 'USER';
122   if (cnt > 0)
123     return MR_IN_USE;
124   EXEC SQL SELECT COUNT(acl_id) INTO :cnt FROM hostaccess
125     WHERE acl_id = :id AND acl_type = 'USER';
126   if (cnt > 0)
127     return MR_IN_USE;
128   if (dbms_errno)
129     return mr_errcode;
130   return MR_SUCCESS;
131 }
132
133
134 /* setup_spop: verify that there is already a valid POP machine_id in the
135  * pop_id field.  Also take care of keeping track of the post office usage.
136  */
137 int setup_spop(struct query *q, char *argv[], client *cl)
138 {
139   EXEC SQL BEGIN DECLARE SECTION;
140   int id, mid;
141   char type[USERS_POTYPE_SIZE];
142   EXEC SQL END DECLARE SECTION;
143
144   id = *(int *)argv[0];
145   EXEC SQL SELECT potype, pop_id INTO :type, :mid FROM users
146     WHERE users_id = :id;
147   if (sqlca.sqlerrd[2] == 0)
148     return MR_MACHINE;
149   EXEC SQL SELECT mach_id INTO :mid FROM machine
150     WHERE mach_id = :mid;
151   if (sqlca.sqlerrd[2] == 0)
152     return MR_MACHINE;
153   if (strcmp(strtrim(type), "POP"))
154     set_pop_usage(mid, 1);
155   return MR_SUCCESS;
156 }
157
158
159 /* setup_dpob:  Take care of keeping track of the post office usage.
160  */
161 int setup_dpob(struct query *q, char *argv[], client *cl)
162 {
163   EXEC SQL BEGIN DECLARE SECTION;
164   int id, user;
165   char type[USERS_POTYPE_SIZE];
166   EXEC SQL END DECLARE SECTION;
167
168   user = *(int *)argv[0];
169   EXEC SQL SELECT potype, pop_id INTO :type, :id FROM users
170     WHERE users_id = :user;
171   if (dbms_errno)
172     return mr_errcode;
173
174   if (!strcmp(strtrim(type), "POP"))
175     set_pop_usage(id, -1);
176   return MR_SUCCESS;
177 }
178
179
180 /* setup_dmac - verify that the machine is no longer being referenced
181  * and may safely be deleted.
182  */
183
184 int setup_dmac(struct query *q, char *argv[], client *cl)
185 {
186   EXEC SQL BEGIN DECLARE SECTION;
187   int flag, id, cnt;
188   EXEC SQL END DECLARE SECTION;
189
190   id = *(int *)argv[0];
191
192   EXEC SQL SELECT status INTO :flag FROM machine
193     WHERE mach_id = :id;
194   if (flag != 3)
195     return MR_IN_USE;
196   EXEC SQL SELECT COUNT(login) INTO :cnt FROM users
197     WHERE potype = 'POP' AND pop_id = :id;
198   if (cnt > 0)
199     return MR_IN_USE;
200   EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM serverhosts
201     WHERE mach_id = :id;
202   if (cnt > 0)
203     return MR_IN_USE;
204   EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM nfsphys
205     WHERE mach_id = :id;
206   if (cnt > 0)
207     return MR_IN_USE;
208   EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM hostaccess
209     WHERE mach_id = :id;
210   if (cnt > 0)
211     return MR_IN_USE;
212   EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printcap
213     WHERE mach_id = :id;
214   if (cnt > 0)
215     return MR_IN_USE;
216   EXEC SQL SELECT COUNT(quotaserver) INTO :cnt FROM printcap
217     WHERE quotaserver = :id;
218   if (cnt > 0)
219     return MR_IN_USE;
220   EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM palladium
221     WHERE mach_id = :id;
222   if (cnt > 0)
223     return MR_IN_USE;
224   EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM hostalias
225     WHERE mach_id = :id;
226   if (cnt > 0)
227     return MR_IN_USE;
228
229   EXEC SQL DELETE FROM mcmap WHERE mach_id = :id;
230   if (dbms_errno)
231     return mr_errcode;
232   return MR_SUCCESS;
233 }
234
235
236 /* setup_dsnt - verify that the subnet is no longer being referenced
237  * and may safely be deleted.
238  */
239
240 int setup_dsnt(struct query *q, char *argv[], client *cl)
241 {
242   EXEC SQL BEGIN DECLARE SECTION;
243   int id, cnt = 0;
244   EXEC SQL END DECLARE SECTION;
245
246   id = *(int *)argv[0];
247   EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM machine
248     WHERE snet_id = :id;
249   if (cnt > 0)
250     return MR_IN_USE;
251   return MR_SUCCESS;
252 }
253
254
255 /* setup_dclu - verify that the cluster is no longer being referenced
256  * and may safely be deleted.
257  */
258
259 int setup_dclu(struct query *q, char *argv[], client *cl)
260 {
261   EXEC SQL BEGIN DECLARE SECTION;
262   int id, cnt;
263   EXEC SQL END DECLARE SECTION;
264
265   id = *(int *)argv[0];
266   EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM mcmap
267     WHERE clu_id = :id;
268   if (cnt > 0)
269     return MR_IN_USE;
270   EXEC SQL SELECT COUNT(clu_id) INTO :cnt FROM svc
271     WHERE clu_id = :id;
272   if (cnt > 0)
273     return MR_IN_USE;
274   if (dbms_errno)
275     return mr_errcode;
276   return MR_SUCCESS;
277 }
278
279
280 /* setup_alis - if argv[5] is non-zero and argv[6] is UNIQUE_ID, then allocate
281  * a new gid and put it in argv[6].  Otherwise if argv[6] is UNIQUE_ID but
282  * argv[5] is not, then remember that UNIQUE_ID is being stored by putting
283  * a -1 there.  Remember that this is also used for ulis, with the indexes
284  * at 6 & 7.  Also check that the list name does not contain uppercase
285  * characters, control characters, @, or :.
286  */
287
288 static int badlistchars[] = {
289   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
290   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
291   1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
292   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, /* 0 - ? */
293   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ - O */
294   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, /* P - _ */
295   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
296   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
297   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
298   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
299   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
300   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
301   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
302   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
303   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
304   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
305 };
306
307 int setup_alis(struct query *q, char *argv[], client *cl)
308 {
309   EXEC SQL BEGIN DECLARE SECTION;
310   int ngid, cnt;
311   char *name;
312   EXEC SQL END DECLARE SECTION;
313   unsigned char *p;
314   int idx, err;
315
316   if (!strcmp(q->shortname, "alis"))
317     idx = 0;
318   else if (!strcmp(q->shortname, "ulis"))
319     idx = 1;
320   name = argv[idx];
321
322   if (idx == 1)
323     {
324       EXEC SQL BEGIN DECLARE SECTION;
325       int lid = *(int *)argv[0];
326       EXEC SQL END DECLARE SECTION;
327
328       if (acl_access_check(lid, cl))
329         return MR_PERM;
330     }
331
332   for (p = (unsigned char *) name; *p; p++)
333     {
334       if (badlistchars[*p])
335         return MR_BAD_CHAR;
336     }
337
338   /* Check that it doesn't conflict with a pre-existing weirdly-cased
339    * name. */
340   EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
341     WHERE LOWER(name) = :name AND name != :name;
342   if (cnt)
343     return MR_EXISTS;
344
345   if (!strcmp(argv[6 + idx], UNIQUE_GID) || atoi(argv[6 + idx]) == -1)
346     {
347       if (atoi(argv[5 + idx]))
348         {
349           if ((err = set_next_object_id("gid", LIST_TABLE, 1)))
350             return err;
351           EXEC SQL SELECT value INTO :ngid FROM numvalues
352             WHERE name = 'gid';
353           if (dbms_errno)
354             return mr_errcode;
355           sprintf(argv[6 + idx], "%d", ngid);
356         }
357       else
358         strcpy(argv[6 + idx], "-1");
359     }
360
361   if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
362     return mr_errcode;
363
364   return MR_SUCCESS;
365 }
366
367
368 /* setup_dlis - verify that the list is no longer being referenced
369  * and may safely be deleted.
370  */
371
372 int setup_dlis(struct query *q, char *argv[], client *cl)
373 {
374   int id;
375   EXEC SQL BEGIN DECLARE SECTION;
376   int cnt;
377   EXEC SQL END DECLARE SECTION;
378
379   id = *(int *)argv[0];
380
381   EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
382     WHERE member_id = :id AND member_type = 'LIST';
383   if (cnt > 0)
384     return MR_IN_USE;
385
386   EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
387     WHERE member_id = :id AND member_type = 'LIST';
388   if (cnt > 0)
389     return MR_IN_USE;
390
391   EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
392     WHERE list_id = :id;
393   if (cnt > 0)
394     return MR_IN_USE;
395
396   EXEC SQL SELECT COUNT(label) INTO :cnt FROM filesys WHERE owners = :id;
397   if (cnt > 0)
398     return MR_IN_USE;
399
400   EXEC SQL SELECT COUNT(tag) INTO :cnt FROM capacls WHERE list_id = :id;
401   if (cnt > 0)
402     return MR_IN_USE;
403
404   EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
405     WHERE acl_id = :id AND acl_type = 'LIST' AND list_id != :id;
406   if (cnt > 0)
407     return MR_IN_USE;
408
409   EXEC SQL SELECT COUNT(name) INTO :cnt FROM servers
410     WHERE acl_id = :id AND acl_type = 'LIST';
411   if (cnt > 0)
412     return MR_IN_USE;
413
414   EXEC SQL SELECT COUNT(entity_id) INTO :cnt FROM quota
415     WHERE entity_id = :id AND type = 'GROUP';
416   if (cnt > 0)
417     return MR_IN_USE;
418
419   EXEC SQL SELECT COUNT(acl_id) INTO :cnt FROM hostaccess
420     WHERE acl_id = :id AND acl_type = 'LIST';
421   if (cnt > 0)
422     return MR_IN_USE;
423
424   EXEC SQL SELECT COUNT(class) INTO :cnt FROM zephyr z
425     WHERE z.xmt_type = 'LIST' AND z.xmt_id = :id
426     OR z.sub_type = 'LIST' AND z.sub_id = :id
427     OR z.iws_type = 'LIST' AND z.iws_id = :id
428     OR z.iui_type = 'LIST' AND z.iui_id = :id;
429   if (cnt > 0)
430     return MR_IN_USE;
431
432   return MR_SUCCESS;
433 }
434
435
436 /* setup_dsin - verify that the service is no longer being referenced
437  * and may safely be deleted.
438  */
439
440 int setup_dsin(struct query *q, char *argv[], client *cl)
441 {
442   EXEC SQL BEGIN DECLARE SECTION;
443   int ec, cnt;
444   char *svrname;
445   EXEC SQL END DECLARE SECTION;
446
447   svrname = argv[0];
448   EXEC SQL SELECT COUNT(service) INTO :cnt FROM serverhosts
449     WHERE service = UPPER(:svrname);
450   if (cnt > 0)
451     return MR_IN_USE;
452
453   EXEC SQL SELECT inprogress INTO :ec FROM servers
454     WHERE name = UPPER(:svrname);
455   if (dbms_errno)
456     return mr_errcode;
457   if (ec)
458     return MR_IN_USE;
459
460   return MR_SUCCESS;
461 }
462
463
464 /* setup_dshi - verify that the service-host is no longer being referenced
465  * and may safely be deleted.
466  */
467
468 int setup_dshi(struct query *q, char *argv[], client *cl)
469 {
470   EXEC SQL BEGIN DECLARE SECTION;
471   int id, ec;
472   char *svrname;
473   EXEC SQL END DECLARE SECTION;
474
475   svrname = argv[0];
476   id = *(int *)argv[1];
477
478   EXEC SQL SELECT inprogress INTO :ec FROM serverhosts
479     WHERE service = UPPER(:svrname) AND mach_id = :id;
480   if (dbms_errno)
481     return mr_errcode;
482   if (ec)
483     return MR_IN_USE;
484
485   return MR_SUCCESS;
486 }
487
488
489 /**
490  ** setup_add_filesys - verify existance of referenced file systems
491  **
492  ** Inputs:     Add
493  **   argv[1] - type
494  **   argv[2] - mach_id
495  **   argv[3] - name
496  **   argv[5] - rwaccess
497  **
498  ** Description:
499  **   - for type = RVD:
500  **        * allow anything
501  **   - for type = NFS:
502  **        * extract directory prefix from name
503  **        * verify mach_id/dir in nfsphys
504  **        * verify rwaccess in {r, w, R, W}
505  **
506  **  Side effect: sets variable _var_phys_id to the ID of the physical
507  **     filesystem (nfsphys_id for NFS, 0 for RVD)
508  **
509  ** Errors:
510  **   MR_NFS - specified directory not exported
511  **   MR_FILESYS_ACCESS - invalid filesys access
512  **
513  **/
514
515 EXEC SQL BEGIN DECLARE SECTION;
516 int _var_phys_id;
517 EXEC SQL END DECLARE SECTION;
518
519 int setup_afil(struct query *q, char *argv[], client *cl)
520 {
521   char *type, *name;
522   int mach_id;
523   EXEC SQL BEGIN DECLARE SECTION;
524   int ok;
525   char ftype[FILESYS_TYPE_SIZE + 10], *rwaccess;
526   EXEC SQL END DECLARE SECTION;
527
528   type = argv[1];
529   mach_id = *(int *)argv[2];
530   name = argv[3];
531   rwaccess = argv[5];
532   _var_phys_id = 0;
533
534   sprintf(ftype, "fs_access_%s", type);
535   EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
536     WHERE name = :ftype AND type = 'TYPE' and trans = :rwaccess;
537   if (dbms_errno)
538     return mr_errcode;
539   if (ok == 0)
540     return MR_FILESYS_ACCESS;
541
542   if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
543     return mr_errcode;
544
545   if (!strcmp(type, "NFS"))
546     return check_nfs(mach_id, name, rwaccess);
547
548   return MR_SUCCESS;
549 }
550
551
552 /* Verify the arguments, depending on the FStype.  Also, if this is an
553  * NFS filesystem, then update any quotas for that filesystem to reflect
554  * the new phys_id.
555  */
556
557 int setup_ufil(struct query *q, char *argv[], client *cl)
558 {
559   int mach_id, status;
560   char *type, *name;
561   EXEC SQL BEGIN DECLARE SECTION;
562   int fid, total, who, ok;
563   char *entity, ftype[FILESYS_TYPE_SIZE + 10], *access;
564   short int total_null;
565   EXEC SQL END DECLARE SECTION;
566
567   _var_phys_id = 0;
568   type = argv[2];
569   mach_id = *(int *)argv[3];
570   name = argv[4];
571   access = argv[6];
572   fid = *(int *)argv[0];
573   who = cl->client_id;
574   entity = cl->entity;
575
576   sprintf(ftype, "fs_access_%s", type);
577   EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
578     WHERE name = :ftype AND type = 'TYPE' AND trans = :access;
579   if (dbms_errno)
580     return mr_errcode;
581   if (ok == 0)
582     return MR_FILESYS_ACCESS;
583
584   EXEC SQL SELECT type INTO :ftype FROM filesys
585     WHERE filsys_id = :fid;
586   if (dbms_errno)
587     return mr_errcode;
588
589   if (!strcmp(type, "NFS"))
590     {
591       status = check_nfs(mach_id, name, access);
592       EXEC SQL UPDATE quota SET phys_id = :_var_phys_id
593         WHERE filsys_id = :fid;
594       if (dbms_errno)
595         return mr_errcode;
596       return status;
597     }
598   else if (!strcmp(type, "AFS") && strcmp(strtrim(ftype), "AFS")
599            && strcmp(strtrim(ftype), "ERR"))
600     {
601       total = 0;
602       EXEC SQL DELETE FROM quota
603         WHERE type = 'ANY' AND filsys_id = :fid;
604       EXEC SQL SELECT SUM (quota) INTO :total:total_null FROM quota
605         WHERE filsys_id = :fid AND phys_id != 0;
606       if (dbms_errno)
607         return mr_errcode;
608       if (!total_null && (total != 0))
609         {
610           EXEC SQL INSERT INTO quota (quota, filsys_id, phys_id, entity_id,
611                                       type, modtime, modby, modwith)
612             VALUES (:total, :fid, 0, 0, 'ANY', SYSDATE, :who, :entity);
613           if (dbms_errno)
614             return mr_errcode;
615         }
616     }
617   else
618     {
619       EXEC SQL UPDATE quota SET phys_id = 0 WHERE filsys_id = :fid;
620       if (dbms_errno)
621         return mr_errcode;
622     }
623   return MR_SUCCESS;
624 }
625
626
627 /* Find the NFS physical partition that the named directory is on.
628  * This is done by comparing the dir against the mount point of the
629  * partition.  To make sure we get the correct match when there is
630  * more than one, we sort the query in reverse order by dir name.
631  */
632
633 int check_nfs(int mach_id, char *name, char *access)
634 {
635   EXEC SQL BEGIN DECLARE SECTION;
636   char dir[NFSPHYS_DIR_SIZE];
637   int mid = mach_id;
638   EXEC SQL END DECLARE SECTION;
639   int status;
640   char *cp1;
641   char *cp2;
642
643   status = MR_NFS;
644   EXEC SQL DECLARE csr101 CURSOR FOR
645     SELECT nfsphys_id, dir FROM nfsphys
646     WHERE mach_id = :mid
647     ORDER BY 2 DESC;
648   if (dbms_errno)
649     return mr_errcode;
650   EXEC SQL OPEN csr101;
651   if (dbms_errno)
652     return mr_errcode;
653   while (1)
654     {
655       EXEC SQL FETCH csr101 INTO :_var_phys_id, :dir;
656       if (sqlca.sqlcode)
657         break;
658       cp1 = name;
659       cp2 = strtrim(dir);
660       while (*cp2)
661         {
662           if (*cp1++ != *cp2)
663             break;
664           cp2++;
665         }
666       if (!*cp2)
667         {
668           status = MR_SUCCESS;
669           break;
670         }
671     }
672   EXEC SQL CLOSE csr101;
673   if (dbms_errno)
674     return mr_errcode;
675   return status;
676 }
677
678
679 /* setup_dfil: free any quota records and fsgroup info associated with
680  * a filesystem when it is deleted.  Also adjust the allocation numbers.
681  */
682
683 int setup_dfil(struct query *q, char **argv, client *cl)
684 {
685   EXEC SQL BEGIN DECLARE SECTION;
686   int id, total, phys_id;
687   short int none;
688   EXEC SQL END DECLARE SECTION;
689
690   id = *(int *)argv[0];
691   EXEC SQL SELECT SUM (quota) INTO :total:none FROM quota
692     WHERE filsys_id = :id;
693
694   if (none)
695     total = 0;
696
697   /** What if there are multiple phys_id's per f/s? (bad data) **/
698   EXEC SQL SELECT phys_id INTO :phys_id FROM filesys
699     WHERE filsys_id = :id;
700   EXEC SQL UPDATE nfsphys SET allocated = allocated - :total
701     WHERE nfsphys_id = :phys_id;
702
703   if (!none)
704     EXEC SQL DELETE FROM quota WHERE filsys_id = :id;
705   EXEC SQL DELETE FROM fsgroup WHERE filsys_id = :id;
706   EXEC SQL DELETE FROM fsgroup WHERE group_id = :id;
707   if (dbms_errno)
708     return mr_errcode;
709   return MR_SUCCESS;
710 }
711
712
713 /* setup_dnfp: check to see that the nfs physical partition does not have
714  * any filesystems assigned to it before allowing it to be deleted.
715  */
716
717 int setup_dnfp(struct query *q, char **argv, client *cl)
718 {
719   EXEC SQL BEGIN DECLARE SECTION;
720   int id, cnt;
721   char *dir;
722   EXEC SQL END DECLARE SECTION;
723
724   id = *(int *)argv[0];
725   dir = argv[1];
726   EXEC SQL SELECT count(fs.rowid) INTO :cnt FROM filesys fs, nfsphys np
727     WHERE fs.mach_id = :id AND fs.phys_id = np.nfsphys_id
728     AND np.mach_id = :id AND np.dir = :dir;
729   if (cnt > 0)
730     return MR_IN_USE;
731   if (dbms_errno)
732     return mr_errcode;
733   return MR_SUCCESS;
734 }
735
736
737 /* setup_dqot: Remove allocation from nfsphys before deleting quota.
738  *   argv[0] = filsys_id
739  *   argv[1] = type if "update_quota" or "delete_quota"
740  *   argv[2 or 1] = users_id or list_id
741  */
742
743 int setup_dqot(struct query *q, char **argv, client *cl)
744 {
745   EXEC SQL BEGIN DECLARE SECTION;
746   int quota, fs, id, physid;
747   char *qtype;
748   EXEC SQL END DECLARE SECTION;
749
750   fs = *(int *)argv[0];
751   if (!strcmp(q->name, "update_quota") || !strcmp(q->name, "delete_quota"))
752     {
753       qtype = argv[1];
754       id = *(int *)argv[2];
755     }
756   else
757     {
758       qtype = "USER";
759       id = *(int *)argv[1];
760     }
761
762   EXEC SQL SELECT quota INTO :quota FROM quota
763     WHERE type = :qtype AND entity_id = :id AND filsys_id = :fs;
764   EXEC SQL SELECT phys_id INTO :physid FROM filesys
765     WHERE filsys_id = :fs;
766   EXEC SQL UPDATE nfsphys SET allocated = allocated - :quota
767     WHERE nfsphys_id = :physid;
768
769   if (dbms_errno)
770     return mr_errcode;
771   return MR_SUCCESS;
772 }
773
774
775 /* prefetch_value():
776  * This routine fetches an appropriate value from the numvalues table.
777  * It is a little hack to get around the fact that SQL doesn't let you
778  * do something like INSERT INTO table (foo) VALUES (other_table.bar).
779  *
780  * It is called from the query table as (*v->pre_rtn)(q, Argv, cl) or
781  * from within a setup_...() routine with the appropriate arguments.
782  *
783  * Correct functioning of this routine may depend on the assumption
784  * that this query is an APPEND.
785  */
786
787 int prefetch_value(struct query *q, char **argv, client *cl)
788 {
789   EXEC SQL BEGIN DECLARE SECTION;
790   char *name = q->validate->object_id;
791   int value;
792   EXEC SQL END DECLARE SECTION;
793   int status, limit, argc;
794
795   /* set next object id, limiting it if necessary */
796   if (!strcmp(name, "unix_uid") || !strcmp(name, "gid"))
797     limit = 1; /* So far as I know, this isn't needed.  Just CMA. */
798   else
799     limit = 0;
800   if ((status = set_next_object_id(name, q->rtable, limit)) != MR_SUCCESS)
801     return status;
802
803   /* fetch object id */
804   EXEC SQL SELECT value INTO :value FROM numvalues WHERE name = :name;
805   if (dbms_errno)
806     return mr_errcode;
807   if (sqlca.sqlerrd[2] != 1)
808     return MR_INTERNAL;
809
810   argc = q->argc + q->vcnt;   /* end of Argv for APPENDs */
811   sprintf(argv[argc], "%d", value);
812
813   return MR_SUCCESS;
814 }
815
816 /* prefetch_filesys():
817  * Fetches the phys_id from filesys based on the filsys_id in argv[0].
818  * Appends the filsys_id and the phys_id to the argv so they can be
819  * referenced in an INSERT into a table other than filesys.  Also
820  * see comments at prefetch_value().
821  *
822  * Assumes the existence of a row where filsys_id = argv[0], since a
823  * filesys label has already been resolved to a filsys_id.
824  */
825 int prefetch_filesys(struct query *q, char **argv, client *cl)
826 {
827   EXEC SQL BEGIN DECLARE SECTION;
828   int fid, phid;
829   EXEC SQL END DECLARE SECTION;
830   int argc;
831
832   fid = *(int *)argv[0];
833   EXEC SQL SELECT phys_id INTO :phid FROM filesys WHERE filsys_id = :fid;
834   if (dbms_errno)
835     return mr_errcode;
836
837   argc = q->argc + q->vcnt;
838   sprintf(argv[argc++], "%d", phid);
839   sprintf(argv[argc], "%d", fid);
840
841   return MR_SUCCESS;
842 }
843
844
845 /* setup_ahst():
846  */
847
848 int setup_ahst(struct query *q, char **argv, client *cl)
849 {
850   EXEC SQL BEGIN DECLARE SECTION;
851   char *name, oldname[MACHINE_NAME_SIZE], vendor[MACHINE_VENDOR_SIZE];
852   char model[MACHINE_MODEL_SIZE], os[MACHINE_OS_SIZE];
853   int value, id, ssaddr, smask, shigh, slow, cnt;
854   unsigned int saddr, mask, high, low;
855   EXEC SQL END DECLARE SECTION;
856   int row;
857   struct in_addr addr;
858
859   id = *(int *)argv[0];
860
861   if (!strcmp(q->shortname, "uhst"))
862     {
863       row = 1;
864       EXEC SQL SELECT name, vendor, model, os
865         INTO :oldname, :vendor, :model, :os
866         FROM machine WHERE mach_id = :id;
867     }
868   else
869     row = 0;
870
871   /* Sanity check name, vendor, model, and os. */
872   if ((row == 0 || strcasecmp(argv[1], oldname)) &&
873       !hostname_check(argv[row]))
874     return MR_BAD_CHAR;
875   if ((row == 0 || strcasecmp(argv[2], vendor)) &&
876       !hostinfo_check(argv[row + 1], 0))
877     return MR_BAD_CHAR;
878   if ((row == 0 || strcasecmp(argv[3], model)) &&
879       !hostinfo_check(argv[row + 2], 1))
880     return MR_BAD_CHAR;
881   if ((row == 0 || strcasecmp(argv[4], os)) &&
882       !hostinfo_check(argv[row + 3], 0))
883     return MR_BAD_CHAR;
884
885   /* check for duplicate name */
886   name = argv[row];
887   EXEC SQL SELECT count(mach_id) INTO :cnt FROM hostalias
888     WHERE name = UPPER(:name);
889   if (dbms_errno)
890     return mr_errcode;
891   if (cnt != 0)
892     return MR_EXISTS;
893
894   /* check address */
895   if (!strcmp(argv[9 + row], "unassigned"))
896     value = -1;
897   else if (!strcmp(argv[9 + row], "unique"))
898     {
899       if (*(int *)argv[8 + row] == 0)
900         value = -1;
901       else
902         value = -2;
903     }
904   else
905     {
906       value = ntohl(inet_addr(argv[9 + row]));
907       if (value == -1)
908         return MR_ADDRESS;
909     }
910   if (value == 0)
911     return MR_ADDRESS;
912   if (value != -1)
913     {
914       /*
915        * an address or unique was specified.
916        */
917       id = *(int *)argv[8 + row];
918       EXEC SQL SELECT saddr, mask, high, low INTO :ssaddr, :smask,
919         :shigh, :slow FROM subnet WHERE snet_id = :id;
920       if (dbms_errno)
921         return mr_errcode;
922       saddr = (unsigned) ssaddr;
923       mask = (unsigned) smask;
924       high = (unsigned) shigh;
925       low = (unsigned) slow;
926       if (value != -2)
927         {
928           /*
929            * someone specified an IP address for the host record
930            */
931           if ((value & mask) != saddr || value < low || value > high)
932             return MR_ADDRESS;
933           /*
934            * run the address argument through inet_addr(). This
935            * has the effect that any out of bounds host addrs will
936            * be converted to a valid host addr. We do this now
937            * so that the uniqueness check works. We should also
938            * link in an inet_addr() that returns an error for
939            * this case.
940            */
941           addr.s_addr = inet_addr(argv[9 + row]);
942           name = inet_ntoa(addr);
943           EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
944             WHERE address = :name;
945           if (dbms_errno)
946             return mr_errcode;
947           if (cnt > 0)
948             {
949               /*
950                * make IP address is unique. If this a modify request
951                * (row == 1), then we expect one record to exist.
952                */
953               if (row == 0 || (row == 1 && cnt > 1))
954                 return MR_ADDRESS;
955               if (row == 1 && cnt == 1)
956                 {
957                   EXEC SQL SELECT mach_id INTO :id FROM machine
958                     WHERE address = :name;
959                   if (id != *(int *)argv[0])
960                     return MR_ADDRESS;
961                 }
962             }
963         }
964       else
965         {
966           /*
967            * a "unique" address was specified. Walk through the
968            * range specified in the network record, return
969            * error if no room left.
970            */
971           for (id = low; id <= high; id++)
972             {
973               if (((id & 0xff) == 0) || ((id & 0xff) == 255))
974                 continue;
975               addr.s_addr = htonl(id);
976               name = inet_ntoa(addr);
977               EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
978                 WHERE address = :name;
979               if (dbms_errno)
980                 return mr_errcode;
981               if (cnt == 0)
982                 break;
983             }
984           if (cnt != 0)
985             return MR_NO_ID;
986           else
987             value = htonl(id);
988         }
989       /*
990        * we have an address in value. Convert it to a string and store it.
991        */
992       addr.s_addr = htonl(value);
993       strcpy(argv[9 + row], inet_ntoa(addr));
994     }
995   else
996     strcpy(argv[9 + row], "unassigned");
997
998   /* status checking */
999   value = atoi(argv[7 + row]);
1000   if (row == 0 && !(value == 1 || value == 0))
1001     return MR_TYPE;
1002   if (row == 1)
1003     {
1004       id = *(int *)argv[0];
1005       EXEC SQL SELECT status INTO :cnt FROM machine WHERE mach_id = :id;
1006       if (dbms_errno)
1007         return mr_errcode;
1008       if (value != cnt)
1009         {
1010           EXEC SQL UPDATE machine SET statuschange = SYSDATE
1011             WHERE mach_id = :id;
1012         }
1013     }
1014
1015   /*
1016    * If this is an update_host query, we're done.
1017    */
1018   if (row == 1)
1019     return MR_SUCCESS;
1020
1021   /*
1022    * For an add_host query, allocate and fill in a new machine id,
1023    * and then insert the creator id.
1024    */
1025   if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
1026     return mr_errcode;
1027
1028   sprintf(argv[q->argc + q->vcnt + 1], "%d", cl->client_id);
1029   return MR_SUCCESS;
1030 }
1031
1032
1033 /* setup_ahal():
1034  */
1035
1036 int setup_ahal(struct query *q, char **argv, client *cl)
1037 {
1038   EXEC SQL BEGIN DECLARE SECTION;
1039   char *name;
1040   int cnt;
1041   EXEC SQL END DECLARE SECTION;
1042   char *p;
1043
1044   name = argv[0];
1045   if (!hostname_check(argv[0]))
1046     return MR_BAD_CHAR;
1047
1048   EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine WHERE
1049     name = UPPER(:name);
1050   if (dbms_errno)
1051     return mr_errcode;
1052   if (cnt > 0)
1053     return MR_EXISTS;
1054
1055   return MR_SUCCESS;
1056 }
1057
1058 /* hostname_check()
1059  * validate the rfc1035/rfc1123-ness of a hostname
1060  */
1061
1062 int hostname_check(char *name)
1063 {
1064   char *p;
1065   int count;
1066
1067   /* Sanity check name: must contain only letters, numerals, and
1068    * hyphen, and not start or end with a hyphen. Also make sure no
1069    * label (the thing the .s seperate) is longer than 63 characters.
1070    */
1071
1072   for (p = name, count = 0; *p; p++)
1073     {
1074       count++;
1075       if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1076           (*p == '-' && p[1] == '.'))
1077         return 0;
1078       if (*p == '.')
1079         count = 0;
1080       if (count == 64)
1081         return 0;
1082     }
1083   if (*(p - 1) == '-')
1084     return 0;
1085   return 1;
1086 }
1087
1088 int hostinfo_check(char *info, int num)
1089 {
1090   char *p;
1091
1092   if (!*info)
1093     return 1;
1094
1095   /* Sanity check host hostinfo: must start with a letter (or number
1096    * if num is true), contain only letters, numerals, and hyphen, and
1097    * not end with a hyphen.
1098    */
1099
1100   if (!isalpha(*info) && (!num || !isdigit(*info)))
1101     return 0;
1102   for (p = info; *p; p++)
1103     {
1104       if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1105           (*p == '-' && p[1] == '.'))
1106         return 0;
1107     }
1108   if (!isalnum(*(p - 1)))
1109     return 1;
1110 }
This page took 0.116562 seconds and 5 git commands to generate.