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