]> andersk Git - moira.git/blob - server/qsetup.pc
Add winconsoleshell to incremental program arg list.
[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;
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   /* Sanity check name, vendor, model, and os. */
898   if ((row == 0 || strcasecmp(argv[1], oldname)) &&
899       !hostname_check(argv[row]))
900     return MR_BAD_CHAR;
901   if ((row == 0 || strcasecmp(argv[2], vendor)) &&
902       !hostinfo_check(argv[row + 1], 0))
903     return MR_BAD_CHAR;
904   if ((row == 0 || strcasecmp(argv[3], model)) &&
905       !hostinfo_check(argv[row + 2], 1))
906     return MR_BAD_CHAR;
907   if ((row == 0 || strcasecmp(argv[4], os)) &&
908       !hostinfo_check(argv[row + 3], 0))
909     return MR_BAD_CHAR;
910
911   /* check for duplicate name */
912   name = argv[row];
913   EXEC SQL SELECT count(mach_id) INTO :cnt FROM hostalias
914     WHERE name = UPPER(:name);
915   if (dbms_errno)
916     return mr_errcode;
917   if (cnt != 0)
918     return MR_EXISTS;
919
920   /* check address */
921   if (!strcmp(argv[9 + row], "unassigned"))
922     value = -1;
923   else if (!strcmp(argv[9 + row], "unique"))
924     {
925       if (*(int *)argv[8 + row] == 0)
926         value = -1;
927       else
928         value = -2;
929     }
930   else
931     {
932       value = ntohl(inet_addr(argv[9 + row]));
933       if (value == -1)
934         return MR_ADDRESS;
935     }
936   if (value == 0)
937     return MR_ADDRESS;
938   if (value != -1)
939     {
940       /*
941        * an address or unique was specified.
942        */
943       id = *(int *)argv[8 + row];
944       EXEC SQL SELECT saddr, mask, high, low INTO :ssaddr, :smask,
945         :shigh, :slow FROM subnet WHERE snet_id = :id;
946       if (dbms_errno)
947         return mr_errcode;
948       saddr = (unsigned) ssaddr;
949       mask = (unsigned) smask;
950       high = (unsigned) shigh;
951       low = (unsigned) slow;
952       if (value != -2)
953         {
954           /*
955            * someone specified an IP address for the host record
956            */
957           if ((value & mask) != saddr || value < low || value > high)
958             return MR_ADDRESS;
959           /*
960            * run the address argument through inet_addr(). This
961            * has the effect that any out of bounds host addrs will
962            * be converted to a valid host addr. We do this now
963            * so that the uniqueness check works. We should also
964            * link in an inet_addr() that returns an error for
965            * this case.
966            */
967           addr.s_addr = inet_addr(argv[9 + row]);
968           name = inet_ntoa(addr);
969           EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
970             WHERE address = :name;
971           if (dbms_errno)
972             return mr_errcode;
973           if (cnt > 0)
974             {
975               /*
976                * make IP address is unique. If this a modify request
977                * (row == 1), then we expect one record to exist.
978                */
979               if (row == 0 || (row == 1 && cnt > 1))
980                 return MR_ADDRESS;
981               if (row == 1 && cnt == 1)
982                 {
983                   EXEC SQL SELECT mach_id INTO :id FROM machine
984                     WHERE address = :name;
985                   if (id != *(int *)argv[0])
986                     return MR_ADDRESS;
987                 }
988             }
989         }
990       else
991         {
992           /*
993            * a "unique" address was specified. Walk through the
994            * range specified in the network record, return
995            * error if no room left.
996            */
997           for (id = low; id <= high; id++)
998             {
999               if (((id & 0xff) == 0) || ((id & 0xff) == 255))
1000                 continue;
1001               addr.s_addr = htonl(id);
1002               name = inet_ntoa(addr);
1003               EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
1004                 WHERE address = :name;
1005               if (dbms_errno)
1006                 return mr_errcode;
1007               if (cnt == 0)
1008                 break;
1009             }
1010           if (cnt != 0)
1011             return MR_NO_ID;
1012           else
1013             value = htonl(id);
1014         }
1015       /*
1016        * we have an address in value. Convert it to a string and store it.
1017        */
1018       addr.s_addr = htonl(value);
1019       strcpy(argv[9 + row], inet_ntoa(addr));
1020     }
1021   else
1022     strcpy(argv[9 + row], "unassigned");
1023
1024   /* status checking */
1025   value = atoi(argv[7 + row]);
1026   if (row == 0 && !(value == 1 || value == 0))
1027     return MR_TYPE;
1028   if (row == 1)
1029     {
1030       id = *(int *)argv[0];
1031       EXEC SQL SELECT status INTO :cnt FROM machine WHERE mach_id = :id;
1032       if (dbms_errno)
1033         return mr_errcode;
1034       if (value != cnt)
1035         {
1036           EXEC SQL UPDATE machine SET statuschange = SYSDATE
1037             WHERE mach_id = :id;
1038         }
1039     }
1040
1041   /*
1042    * If this is an update_host query, we're done.
1043    */
1044   if (row == 1)
1045     return MR_SUCCESS;
1046
1047   /*
1048    * For an add_host query, allocate and fill in a new machine id,
1049    * and then insert the creator id.
1050    */
1051   if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
1052     return mr_errcode;
1053
1054   sprintf(argv[q->argc + q->vcnt + 1], "%d", cl->client_id);
1055   return MR_SUCCESS;
1056 }
1057
1058
1059 /* setup_ahal():
1060  */
1061
1062 int setup_ahal(struct query *q, char **argv, client *cl)
1063 {
1064   EXEC SQL BEGIN DECLARE SECTION;
1065   char *name;
1066   int cnt;
1067   EXEC SQL END DECLARE SECTION;
1068   char *p;
1069
1070   name = argv[0];
1071   if (!hostname_check(argv[0]))
1072     return MR_BAD_CHAR;
1073
1074   EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine WHERE
1075     name = UPPER(:name);
1076   if (dbms_errno)
1077     return mr_errcode;
1078   if (cnt > 0)
1079     return MR_EXISTS;
1080
1081   return MR_SUCCESS;
1082 }
1083
1084 /* setup_uhha(): Check characters in hwaddr, and make sure it's not
1085  * a duplicate.
1086  */
1087 int setup_uhha(struct query *q, char **argv, client *cl)
1088 {
1089   EXEC SQL BEGIN DECLARE SECTION;
1090   char *hwaddr = argv[1];
1091   int count;
1092   EXEC SQL END DECLARE SECTION;
1093   char *p;
1094
1095   if (*hwaddr && strcasecmp(hwaddr, "unknown"))
1096     {
1097       for (p = hwaddr; *p; p++)
1098         {
1099           if (isupper(*p))
1100             *p = tolower(*p);
1101           if (!isxdigit(*p))
1102             return MR_BAD_CHAR;
1103         }
1104       if (p != hwaddr + 12)
1105         return MR_ADDRESS;
1106
1107       EXEC SQL SELECT COUNT(hwaddr) INTO :count
1108         FROM machine WHERE hwaddr = :hwaddr;
1109       if (count)
1110         return MR_NOT_UNIQUE;
1111     }
1112
1113   return MR_SUCCESS;
1114 }
1115
1116 /* setup_aprn(): Make sure name/duplexname don't conflict with
1117  * anything. If [ANY] was specified for the spooling host, pick the
1118  * least loaded print server that serves this kind of printer.
1119  */
1120 int setup_aprn(struct query *q, char **argv, client *cl)
1121 {
1122   int best = -1, row;
1123   char *p;
1124   EXEC SQL BEGIN DECLARE SECTION;
1125   int mid, usage, count;
1126   char types[STRINGS_STRING_SIZE], *hwaddr, *name, *duplexname, *oldname;
1127   EXEC SQL END DECLARE SECTION;
1128
1129   /* Check for aprn or uprn. */
1130   if (q->type == APPEND)
1131     row = 0;
1132   else
1133     row = 1;
1134
1135   name = argv[PRN_NAME + row];
1136   duplexname = argv[PRN_DUPLEXNAME + row];
1137   oldname = argv[0];
1138
1139   if (!*name)
1140     return MR_BAD_CHAR;
1141   else
1142     {
1143       if (q->type == APPEND)
1144         {
1145           EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1146             WHERE name = :name OR duplexname = :name;
1147         }
1148       else
1149         {
1150           EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1151             WHERE ( name = :name OR duplexname = :name )
1152             AND name != :oldname;
1153         }
1154       if (dbms_errno)
1155         return mr_errcode;
1156       if (count)
1157         return MR_NOT_UNIQUE;
1158     }
1159
1160   if (*duplexname)
1161     {
1162       if (q->type == APPEND)
1163         {
1164           EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1165             WHERE name = :duplexname OR duplexname = :duplexname;
1166         }
1167       else
1168         {
1169           EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1170             WHERE ( name = :duplexname OR duplexname = :duplexname )
1171             AND name != :oldname;
1172         }
1173
1174       if (dbms_errno)
1175         return mr_errcode;
1176       if (count)
1177         return MR_NOT_UNIQUE;
1178     }
1179
1180   if (!strcmp(name, duplexname))
1181     return MR_NOT_UNIQUE;
1182
1183   mid = *(int *)argv[PRN_RM + row];
1184   if (mid == -1)
1185     {
1186       EXEC SQL DECLARE csr_rm CURSOR FOR
1187         SELECT ps.mach_id, s.string FROM printservers ps, strings s
1188         WHERE ps.mach_id IN
1189         ( SELECT mach_id FROM serverhosts WHERE service = 'PRINT'
1190           AND enable = 1 )
1191         AND ps.printer_types = s.string_id;
1192       if (dbms_errno)
1193         return mr_errcode;
1194       EXEC SQL OPEN csr_rm;
1195       if (dbms_errno)
1196         return mr_errcode;
1197
1198       while (1)
1199         {
1200           EXEC SQL FETCH csr_rm INTO :mid, :types;
1201           if (sqlca.sqlcode)
1202             break;
1203
1204           for (p = strtok(types, ", "); p; p = strtok(NULL, ", "))
1205             {
1206               if (!strcasecmp(argv[PRN_TYPE + row], p))
1207                 {
1208                   EXEC SQL SELECT COUNT(name) INTO :usage
1209                     FROM printers WHERE rm = :mid;
1210
1211                   if (best < 0 || usage < best)
1212                     {
1213                       best = usage;
1214                       *(int *)argv[PRN_RM + row] = mid;
1215                       break;
1216                     }
1217                 }
1218             }
1219         }
1220       EXEC SQL CLOSE csr_rm;
1221       if (dbms_errno)
1222         return mr_errcode;
1223
1224       if (best == -1)
1225         return MR_SERVICE;
1226     }
1227   else
1228     {
1229       EXEC SQL SELECT mach_id INTO :mid FROM printservers
1230         WHERE mach_id = :mid;
1231       if (sqlca.sqlcode)
1232         return MR_SERVICE;
1233     }
1234
1235   return MR_SUCCESS;
1236 }
1237
1238 int setup_dpsv(struct query *q, char **argv, client *cl)
1239 {
1240   int id;
1241   EXEC SQL BEGIN DECLARE SECTION;
1242   int cnt;
1243   EXEC SQL END DECLARE SECTION;
1244
1245   id = *(int *)argv[0];
1246
1247   EXEC SQL SELECT COUNT(rm) INTO :cnt FROM printers
1248     WHERE rm = :id;
1249   if (cnt > 0)
1250     return MR_IN_USE;
1251
1252   return MR_SUCCESS;
1253 }
1254
1255 /* hostname_check()
1256  * validate the rfc1035/rfc1123-ness of a hostname
1257  */
1258
1259 int hostname_check(char *name)
1260 {
1261   char *p;
1262   int count;
1263
1264   /* Sanity check name: must contain only letters, numerals, and
1265    * hyphen, and not start or end with a hyphen. Also make sure no
1266    * label (the thing the .s seperate) is longer than 63 characters,
1267    * or empty.
1268    */
1269
1270   for (p = name, count = 0; *p; p++)
1271     {
1272       count++;
1273       if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1274           (*p == '-' && p[1] == '.'))
1275         return 0;
1276       if (*p == '.')
1277         {
1278           if (count == 1)
1279             return 0;
1280           count = 0;
1281         }
1282       if (count == 64)
1283         return 0;
1284     }
1285   if (*(p - 1) == '-')
1286     return 0;
1287   return 1;
1288 }
1289
1290 int hostinfo_check(char *info, int num)
1291 {
1292   char *p;
1293
1294   if (!*info)
1295     return 1;
1296
1297   /* Sanity check host hostinfo: must start with a letter (or number
1298    * if num is true), contain only letters, numerals, and hyphen, and
1299    * not end with a hyphen.
1300    */
1301
1302   if (!isalpha(*info) && (!num || !isdigit(*info)))
1303     return 0;
1304   for (p = info; *p; p++)
1305     {
1306       if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1307           (*p == '-' && p[1] == '.'))
1308         return 0;
1309     }
1310   if (!isalnum(*(p - 1)))
1311     return 1;
1312 }
This page took 7.665026 seconds and 5 git commands to generate.