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