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