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