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