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