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