]> andersk Git - moira.git/blob - server/qsetup.pc
don't allow empty labels in names
[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 palladium
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   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:
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"))
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"))
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;
1101   char *p;
1102   EXEC SQL BEGIN DECLARE SECTION;
1103   int mid, usage, count;
1104   char types[SERVERHOSTS_VALUE3_SIZE], *hwaddr, *name;
1105   EXEC SQL END DECLARE SECTION;
1106
1107   name = argv[PRN_NAME];
1108   if (!*name)
1109     return MR_BAD_CHAR;
1110   else
1111     {
1112       EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1113         WHERE name = :name OR duplexname = :name;
1114       if (dbms_errno)
1115         return mr_errcode;
1116       if (count)
1117         return MR_NOT_UNIQUE;
1118     }
1119
1120   name = argv[PRN_DUPLEXNAME];
1121   if (*name)
1122     {
1123       EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1124         WHERE name = :name OR duplexname = :name;
1125       if (dbms_errno)
1126         return mr_errcode;
1127       if (count)
1128         return MR_NOT_UNIQUE;
1129     }
1130
1131   if (*(int *)argv[PRN_RM] == -1)
1132     {
1133       EXEC SQL DECLARE csr_rm CURSOR FOR
1134         SELECT mach_id, value1, value3 FROM serverhosts
1135         WHERE service = 'PRINT';
1136       if (dbms_errno)
1137         return mr_errcode;
1138       EXEC SQL OPEN csr_rm;
1139       if (dbms_errno)
1140         return mr_errcode;
1141
1142       while (1)
1143         {
1144           EXEC SQL FETCH csr_rm INTO :mid, :usage, :types;
1145           if (sqlca.sqlcode)
1146             break;
1147
1148           if (best > 0 && usage > best)
1149             continue;
1150
1151           for (p = strtok(types, ", "); p; p = strtok(NULL, ", "))
1152             {
1153               if (!strcasecmp(argv[PRN_TYPE], p))
1154                 {
1155                   best = usage;
1156                   *(int *)argv[PRN_RM] = mid;
1157                   break;
1158                 }
1159             }
1160         }
1161       EXEC SQL CLOSE csr_rm;
1162       if (dbms_errno)
1163         return mr_errcode;
1164
1165       if (best == -1)
1166         return MR_SERVICE;
1167     }
1168
1169   return MR_SUCCESS;
1170 }
1171
1172 /* hostname_check()
1173  * validate the rfc1035/rfc1123-ness of a hostname
1174  */
1175
1176 int hostname_check(char *name)
1177 {
1178   char *p;
1179   int count;
1180
1181   /* Sanity check name: must contain only letters, numerals, and
1182    * hyphen, and not start or end with a hyphen. Also make sure no
1183    * label (the thing the .s seperate) is longer than 63 characters,
1184    * or empty.
1185    */
1186
1187   for (p = name, count = 0; *p; p++)
1188     {
1189       count++;
1190       if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1191           (*p == '-' && p[1] == '.'))
1192         return 0;
1193       if (*p == '.')
1194         {
1195           if (count == 1)
1196             return 0;
1197           count = 0;
1198         }
1199       if (count == 64)
1200         return 0;
1201     }
1202   if (*(p - 1) == '-')
1203     return 0;
1204   return 1;
1205 }
1206
1207 int hostinfo_check(char *info, int num)
1208 {
1209   char *p;
1210
1211   if (!*info)
1212     return 1;
1213
1214   /* Sanity check host hostinfo: must start with a letter (or number
1215    * if num is true), contain only letters, numerals, and hyphen, and
1216    * not end with a hyphen.
1217    */
1218
1219   if (!isalpha(*info) && (!num || !isdigit(*info)))
1220     return 0;
1221   for (p = info; *p; p++)
1222     {
1223       if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1224           (*p == '-' && p[1] == '.'))
1225         return 0;
1226     }
1227   if (!isalnum(*(p - 1)))
1228     return 1;
1229 }
This page took 0.237382 seconds and 5 git commands to generate.