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