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