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