]> andersk Git - moira.git/blame - server/qsetup.pc
Allow list owner to remove a list they own from any list.
[moira.git] / server / qsetup.pc
CommitLineData
7ac48069 1/* $Id$
73cf66ba 2 *
7ac48069 3 * Query setup routines
73cf66ba 4 *
7ac48069 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>.
73cf66ba 8 */
9
73cf66ba 10#include <mit-copyright.h>
73cf66ba 11#include "mr_server.h"
03c05291 12#include "query.h"
7ac48069 13#include "qrtn.h"
14
03c05291 15#include <arpa/inet.h>
7ac48069 16#include <netinet/in.h>
17
18#include <ctype.h>
19#include <stdlib.h>
20#include <string.h>
21
73cf66ba 22EXEC SQL INCLUDE sqlca;
73cf66ba 23
7ac48069 24RCSID("$Header$");
25
26extern char *whoami;
03c05291 27extern int dbms_errno, mr_errcode;
73cf66ba 28
29EXEC SQL BEGIN DECLARE SECTION;
30extern char stmt_buf[];
31EXEC SQL END DECLARE SECTION;
32
03c05291 33EXEC SQL WHENEVER SQLERROR DO dbmserr();
34
17f585b5 35int hostname_check(char *name);
36int hostinfo_check(char *name, int num);
03c05291 37int prefetch_value(struct query *q, char **argv, client *cl);
38int check_nfs(int mach_idx, char *name, char *access);
73cf66ba 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
5eaef520 53int setup_ausr(struct query *q, char *argv[], client *cl)
73cf66ba 54{
5eaef520 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;
cca8e7ef 64
186dd63b 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 }
cca8e7ef 77
5eaef520 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);
73cf66ba 86 }
87
5eaef520 88 if (!strcmp(argv[0], UNIQUE_LOGIN) || atoi(argv[row]) == -1)
89 sprintf(argv[0], "#%s", argv[row]);
73cf66ba 90
5eaef520 91 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
92 return mr_errcode;
73cf66ba 93
5eaef520 94 return MR_SUCCESS;
73cf66ba 95}
96
97
98/* setup_dusr - verify that the user is no longer being referenced
99 * and may safely be deleted.
100 */
101
7ac48069 102int setup_dusr(struct query *q, char *argv[], client *cl)
73cf66ba 103{
5eaef520 104 EXEC SQL BEGIN DECLARE SECTION;
105 int flag, id, cnt;
00c3d0fe 106 char resv[USERS_RESERVATIONS_SIZE];
5eaef520 107 EXEC SQL END DECLARE SECTION;
108
109 id = *(int *)argv[0];
110
00c3d0fe 111 /* For now, only allow users to be deleted if their status is 0
112 * and we have no reservations about deleting them.
113 */
114 EXEC SQL SELECT status, reservations INTO :flag, :resv
115 FROM users WHERE users_id = :id;
116 if ((flag != 0 && flag != 4) || *resv)
5eaef520 117 return MR_IN_USE;
118
5eaef520 119 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
120 WHERE member_id = :id AND member_type = 'USER';
121 if (cnt > 0)
122 return MR_IN_USE;
123 EXEC SQL SELECT COUNT(label) INTO :cnt FROM filesys
124 WHERE owner = :id;
125 if (cnt > 0)
126 return MR_IN_USE;
127 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
128 WHERE acl_id = :id AND acl_type = 'USER';
129 if (cnt > 0)
130 return MR_IN_USE;
131 EXEC SQL SELECT COUNT(name) INTO :cnt FROM servers
132 WHERE acl_id = :id AND acl_type = 'USER';
133 if (cnt > 0)
134 return MR_IN_USE;
135 EXEC SQL SELECT COUNT(acl_id) INTO :cnt FROM hostaccess
136 WHERE acl_id = :id AND acl_type = 'USER';
137 if (cnt > 0)
138 return MR_IN_USE;
139 if (dbms_errno)
140 return mr_errcode;
00c3d0fe 141
142 EXEC SQL DELETE FROM quota WHERE entity_id = :id AND type = 'USER';
143 EXEC SQL DELETE FROM krbmap WHERE users_id = :id;
5eaef520 144 return MR_SUCCESS;
73cf66ba 145}
146
147
73cf66ba 148/* setup_dpob: Take care of keeping track of the post office usage.
149 */
7ac48069 150int setup_dpob(struct query *q, char *argv[], client *cl)
73cf66ba 151{
5eaef520 152 EXEC SQL BEGIN DECLARE SECTION;
153 int id, user;
e688520a 154 char type[USERS_POTYPE_SIZE];
5eaef520 155 EXEC SQL END DECLARE SECTION;
156
157 user = *(int *)argv[0];
158 EXEC SQL SELECT potype, pop_id INTO :type, :id FROM users
159 WHERE users_id = :user;
160 if (dbms_errno)
161 return mr_errcode;
162
163 if (!strcmp(strtrim(type), "POP"))
164 set_pop_usage(id, -1);
165 return MR_SUCCESS;
73cf66ba 166}
167
168
169/* setup_dmac - verify that the machine is no longer being referenced
170 * and may safely be deleted.
171 */
172
7ac48069 173int setup_dmac(struct query *q, char *argv[], client *cl)
73cf66ba 174{
5eaef520 175 EXEC SQL BEGIN DECLARE SECTION;
176 int flag, id, cnt;
177 EXEC SQL END DECLARE SECTION;
178
179 id = *(int *)argv[0];
180
181 EXEC SQL SELECT status INTO :flag FROM machine
182 WHERE mach_id = :id;
183 if (flag != 3)
184 return MR_IN_USE;
185 EXEC SQL SELECT COUNT(login) INTO :cnt FROM users
186 WHERE potype = 'POP' AND pop_id = :id;
187 if (cnt > 0)
188 return MR_IN_USE;
189 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM serverhosts
190 WHERE mach_id = :id;
191 if (cnt > 0)
192 return MR_IN_USE;
193 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM nfsphys
194 WHERE mach_id = :id;
195 if (cnt > 0)
196 return MR_IN_USE;
197 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM hostaccess
198 WHERE mach_id = :id;
199 if (cnt > 0)
200 return MR_IN_USE;
2884200f 201 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printers
5eaef520 202 WHERE mach_id = :id;
203 if (cnt > 0)
204 return MR_IN_USE;
2884200f 205 EXEC SQL SELECT COUNT(rm) INTO :cnt FROM printers
206 WHERE rm = :id;
207 if (cnt > 0)
208 return MR_IN_USE;
209 EXEC SQL SELECT COUNT(rq) INTO :cnt FROM printers
210 WHERE rq = :id;
5eaef520 211 if (cnt > 0)
212 return MR_IN_USE;
1a9a0a59 213 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printservers
5eaef520 214 WHERE mach_id = :id;
215 if (cnt > 0)
216 return MR_IN_USE;
217 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM hostalias
218 WHERE mach_id = :id;
219 if (cnt > 0)
220 return MR_IN_USE;
221
222 EXEC SQL DELETE FROM mcmap WHERE mach_id = :id;
223 if (dbms_errno)
224 return mr_errcode;
225 return MR_SUCCESS;
73cf66ba 226}
227
228
229/* setup_dsnt - verify that the subnet is no longer being referenced
230 * and may safely be deleted.
231 */
232
7ac48069 233int setup_dsnt(struct query *q, char *argv[], client *cl)
73cf66ba 234{
5eaef520 235 EXEC SQL BEGIN DECLARE SECTION;
236 int id, cnt = 0;
237 EXEC SQL END DECLARE SECTION;
238
239 id = *(int *)argv[0];
240 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM machine
241 WHERE snet_id = :id;
242 if (cnt > 0)
243 return MR_IN_USE;
244 return MR_SUCCESS;
73cf66ba 245}
246
247
248/* setup_dclu - verify that the cluster is no longer being referenced
249 * and may safely be deleted.
250 */
251
7ac48069 252int setup_dclu(struct query *q, char *argv[], client *cl)
73cf66ba 253{
5eaef520 254 EXEC SQL BEGIN DECLARE SECTION;
255 int id, cnt;
256 EXEC SQL END DECLARE SECTION;
257
258 id = *(int *)argv[0];
259 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM mcmap
260 WHERE clu_id = :id;
261 if (cnt > 0)
262 return MR_IN_USE;
263 EXEC SQL SELECT COUNT(clu_id) INTO :cnt FROM svc
264 WHERE clu_id = :id;
265 if (cnt > 0)
266 return MR_IN_USE;
267 if (dbms_errno)
268 return mr_errcode;
269 return MR_SUCCESS;
73cf66ba 270}
271
272
273/* setup_alis - if argv[5] is non-zero and argv[6] is UNIQUE_ID, then allocate
274 * a new gid and put it in argv[6]. Otherwise if argv[6] is UNIQUE_ID but
275 * argv[5] is not, then remember that UNIQUE_ID is being stored by putting
276 * a -1 there. Remember that this is also used for ulis, with the indexes
277 * at 6 & 7. Also check that the list name does not contain uppercase
278 * characters, control characters, @, or :.
279 */
280
281static int badlistchars[] = {
5eaef520 282 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
283 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
0b452293 284 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, /* SPACE - / */
285 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 0 - ? */
5eaef520 286 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ - O */
0b452293 287 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* P - _ */
5eaef520 288 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
0b452293 289 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
5eaef520 290 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
291 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
292 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
293 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
294 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
295 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
296 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
297 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
73cf66ba 298};
299
5eaef520 300int setup_alis(struct query *q, char *argv[], client *cl)
73cf66ba 301{
5eaef520 302 EXEC SQL BEGIN DECLARE SECTION;
17f585b5 303 int ngid, cnt;
304 char *name;
5eaef520 305 EXEC SQL END DECLARE SECTION;
306 unsigned char *p;
307 int idx, err;
308
309 if (!strcmp(q->shortname, "alis"))
310 idx = 0;
311 else if (!strcmp(q->shortname, "ulis"))
312 idx = 1;
17f585b5 313 name = argv[idx];
5eaef520 314
5a22fdf5 315 if (idx == 1)
316 {
317 EXEC SQL BEGIN DECLARE SECTION;
318 int lid = *(int *)argv[0];
319 EXEC SQL END DECLARE SECTION;
320
321 if (acl_access_check(lid, cl))
322 return MR_PERM;
323 }
324
17f585b5 325 for (p = (unsigned char *) name; *p; p++)
5eaef520 326 {
73cf66ba 327 if (badlistchars[*p])
5eaef520 328 return MR_BAD_CHAR;
329 }
330
17f585b5 331 /* Check that it doesn't conflict with a pre-existing weirdly-cased
332 * name. */
333 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
20315440 334 WHERE LOWER(name) = :name AND name != :name;
17f585b5 335 if (cnt)
336 return MR_EXISTS;
337
5eaef520 338 if (!strcmp(argv[6 + idx], UNIQUE_GID) || atoi(argv[6 + idx]) == -1)
339 {
340 if (atoi(argv[5 + idx]))
341 {
342 if ((err = set_next_object_id("gid", LIST_TABLE, 1)))
343 return err;
344 EXEC SQL SELECT value INTO :ngid FROM numvalues
345 WHERE name = 'gid';
346 if (dbms_errno)
347 return mr_errcode;
348 sprintf(argv[6 + idx], "%d", ngid);
73cf66ba 349 }
5eaef520 350 else
351 strcpy(argv[6 + idx], "-1");
73cf66ba 352 }
353
5eaef520 354 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
355 return mr_errcode;
73cf66ba 356
5eaef520 357 return MR_SUCCESS;
73cf66ba 358}
359
360
361/* setup_dlis - verify that the list is no longer being referenced
362 * and may safely be deleted.
363 */
364
7ac48069 365int setup_dlis(struct query *q, char *argv[], client *cl)
73cf66ba 366{
5eaef520 367 int id;
368 EXEC SQL BEGIN DECLARE SECTION;
369 int cnt;
370 EXEC SQL END DECLARE SECTION;
371
372 id = *(int *)argv[0];
373
374 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
375 WHERE member_id = :id AND member_type = 'LIST';
376 if (cnt > 0)
377 return MR_IN_USE;
378
379 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
380 WHERE member_id = :id AND member_type = 'LIST';
381 if (cnt > 0)
382 return MR_IN_USE;
383
384 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
385 WHERE list_id = :id;
386 if (cnt > 0)
387 return MR_IN_USE;
388
389 EXEC SQL SELECT COUNT(label) INTO :cnt FROM filesys WHERE owners = :id;
390 if (cnt > 0)
391 return MR_IN_USE;
392
393 EXEC SQL SELECT COUNT(tag) INTO :cnt FROM capacls WHERE list_id = :id;
394 if (cnt > 0)
395 return MR_IN_USE;
396
397 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
398 WHERE acl_id = :id AND acl_type = 'LIST' AND list_id != :id;
399 if (cnt > 0)
400 return MR_IN_USE;
401
402 EXEC SQL SELECT COUNT(name) INTO :cnt FROM servers
403 WHERE acl_id = :id AND acl_type = 'LIST';
404 if (cnt > 0)
405 return MR_IN_USE;
406
407 EXEC SQL SELECT COUNT(entity_id) INTO :cnt FROM quota
408 WHERE entity_id = :id AND type = 'GROUP';
409 if (cnt > 0)
410 return MR_IN_USE;
411
412 EXEC SQL SELECT COUNT(acl_id) INTO :cnt FROM hostaccess
413 WHERE acl_id = :id AND acl_type = 'LIST';
414 if (cnt > 0)
415 return MR_IN_USE;
416
417 EXEC SQL SELECT COUNT(class) INTO :cnt FROM zephyr z
418 WHERE z.xmt_type = 'LIST' AND z.xmt_id = :id
419 OR z.sub_type = 'LIST' AND z.sub_id = :id
420 OR z.iws_type = 'LIST' AND z.iws_id = :id
421 OR z.iui_type = 'LIST' AND z.iui_id = :id;
422 if (cnt > 0)
423 return MR_IN_USE;
424
1a9a0a59 425 EXEC SQL SELECT COUNT(name) INTO :cnt FROM printers
426 WHERE lpc_acl = :id OR ac = :id;
427 if (cnt > 0)
428 return MR_IN_USE;
429
430 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printservers
431 WHERE owner_type = 'LIST' AND owner_id = :id
432 OR lpc_acl = :id;
433 if (cnt > 0)
434 return MR_IN_USE;
435
5eaef520 436 return MR_SUCCESS;
73cf66ba 437}
438
439
440/* setup_dsin - verify that the service is no longer being referenced
441 * and may safely be deleted.
442 */
443
7ac48069 444int setup_dsin(struct query *q, char *argv[], client *cl)
73cf66ba 445{
5eaef520 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;
73cf66ba 465}
466
467
468/* setup_dshi - verify that the service-host is no longer being referenced
469 * and may safely be deleted.
470 */
471
7ac48069 472int setup_dshi(struct query *q, char *argv[], client *cl)
73cf66ba 473{
5eaef520 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;
73cf66ba 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
03c05291 500 ** argv[5] - rwaccess
73cf66ba 501 **
502 ** Description:
503 ** - for type = RVD:
504 ** * allow anything
cc1bca5c 505 ** - for type = NFS/IMAP:
73cf66ba 506 ** * extract directory prefix from name
507 ** * verify mach_id/dir in nfsphys
03c05291 508 ** * verify rwaccess in {r, w, R, W}
73cf66ba 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
519EXEC SQL BEGIN DECLARE SECTION;
520int _var_phys_id;
521EXEC SQL END DECLARE SECTION;
522
5eaef520 523int setup_afil(struct query *q, char *argv[], client *cl)
73cf66ba 524{
5eaef520 525 char *type, *name;
526 int mach_id;
527 EXEC SQL BEGIN DECLARE SECTION;
528 int ok;
e688520a 529 char ftype[FILESYS_TYPE_SIZE + 10], *rwaccess;
5eaef520 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
cc1bca5c 549 if (!strcmp(type, "NFS") || !strcmp(type, "IMAP"))
5eaef520 550 return check_nfs(mach_id, name, rwaccess);
551
552 return MR_SUCCESS;
73cf66ba 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
5eaef520 561int setup_ufil(struct query *q, char *argv[], client *cl)
73cf66ba 562{
5eaef520 563 int mach_id, status;
564 char *type, *name;
565 EXEC SQL BEGIN DECLARE SECTION;
566 int fid, total, who, ok;
e688520a 567 char *entity, ftype[FILESYS_TYPE_SIZE + 10], *access;
5eaef520 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
cc1bca5c 593 if (!strcmp(type, "NFS") || !strcmp(type, "IMAP"))
5eaef520 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;
73cf66ba 619 }
73cf66ba 620 }
5eaef520 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;
73cf66ba 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
5eaef520 637int check_nfs(int mach_id, char *name, char *access)
73cf66ba 638{
5eaef520 639 EXEC SQL BEGIN DECLARE SECTION;
e688520a 640 char dir[NFSPHYS_DIR_SIZE];
5eaef520 641 int mid = mach_id;
642 EXEC SQL END DECLARE SECTION;
44d12d58 643 int status;
644 char *cp1;
645 char *cp2;
5eaef520 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)
73cf66ba 667 break;
5eaef520 668 cp2++;
669 }
670 if (!*cp2)
671 {
672 status = MR_SUCCESS;
673 break;
73cf66ba 674 }
675 }
5eaef520 676 EXEC SQL CLOSE csr101;
677 if (dbms_errno)
678 return mr_errcode;
679 return status;
73cf66ba 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
5eaef520 687int setup_dfil(struct query *q, char **argv, client *cl)
73cf66ba 688{
5eaef520 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;
73cf66ba 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
5eaef520 721int setup_dnfp(struct query *q, char **argv, client *cl)
73cf66ba 722{
5eaef520 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;
73cf66ba 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
5eaef520 747int setup_dqot(struct query *q, char **argv, client *cl)
73cf66ba 748{
5eaef520 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];
73cf66ba 764 }
765
5eaef520 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;
73cf66ba 772
5eaef520 773 if (dbms_errno)
774 return mr_errcode;
775 return MR_SUCCESS;
73cf66ba 776}
777
778
7f426981 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 *
5eaef520 784 * It is called from the query table as (*v->pre_rtn)(q, Argv, cl) or
7f426981 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
5eaef520 791int prefetch_value(struct query *q, char **argv, client *cl)
7f426981 792{
5eaef520 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;
7f426981 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 */
5eaef520 829int prefetch_filesys(struct query *q, char **argv, client *cl)
7f426981 830{
5eaef520 831 EXEC SQL BEGIN DECLARE SECTION;
832 int fid, phid;
833 EXEC SQL END DECLARE SECTION;
834 int argc;
7f426981 835
5eaef520 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;
7f426981 840
5eaef520 841 argc = q->argc + q->vcnt;
842 sprintf(argv[argc++], "%d", phid);
843 sprintf(argv[argc], "%d", fid);
7f426981 844
5eaef520 845 return MR_SUCCESS;
7f426981 846}
847
848
849/* setup_ahst():
850 */
851
5eaef520 852int setup_ahst(struct query *q, char **argv, client *cl)
7f426981 853{
5eaef520 854 EXEC SQL BEGIN DECLARE SECTION;
e688520a 855 char *name, oldname[MACHINE_NAME_SIZE], vendor[MACHINE_VENDOR_SIZE];
db9491c6 856 char model[MACHINE_MODEL_SIZE], os[MACHINE_OS_SIZE];
ff98438b 857 int value, id, ssaddr, smask, shigh, slow, cnt;
858 unsigned int saddr, mask, high, low;
5eaef520 859 EXEC SQL END DECLARE SECTION;
860 int row;
861 struct in_addr addr;
5eaef520 862
fde09f2c 863 id = *(int *)argv[0];
864
5eaef520 865 if (!strcmp(q->shortname, "uhst"))
85330553 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 }
5eaef520 872 else
873 row = 0;
874
9e252e6f 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)) &&
17f585b5 880 !hostinfo_check(argv[row + 1], 0))
9e252e6f 881 return MR_BAD_CHAR;
882 if ((row == 0 || strcasecmp(argv[3], model)) &&
17f585b5 883 !hostinfo_check(argv[row + 2], 1))
9e252e6f 884 return MR_BAD_CHAR;
885 if ((row == 0 || strcasecmp(argv[4], os)) &&
17f585b5 886 !hostinfo_check(argv[row + 3], 0))
9e252e6f 887 return MR_BAD_CHAR;
8ca3e341 888
5eaef520 889 /* check for duplicate name */
890 name = argv[row];
891 EXEC SQL SELECT count(mach_id) INTO :cnt FROM hostalias
ad06a10e 892 WHERE name = UPPER(:name);
5eaef520 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;
5482f508 913 }
5eaef520 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];
ff98438b 922 EXEC SQL SELECT saddr, mask, high, low INTO :ssaddr, :smask,
923 :shigh, :slow FROM subnet WHERE snet_id = :id;
5eaef520 924 if (dbms_errno)
925 return mr_errcode;
ff98438b 926 saddr = (unsigned) ssaddr;
927 mask = (unsigned) smask;
928 high = (unsigned) shigh;
929 low = (unsigned) slow;
5eaef520 930 if (value != -2)
931 {
932 /*
933 * someone specified an IP address for the host record
934 */
082466aa 935 if ((value & mask) != saddr || value < low || value > high)
5eaef520 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 */
7ac48069 957 if (row == 0 || (row == 1 && cnt > 1))
5eaef520 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;
7f426981 965 }
966 }
5eaef520 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);
7ac48069 980 name = inet_ntoa(addr);
5eaef520 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;
7f426981 987 }
5eaef520 988 if (cnt != 0)
6715bac2 989 return MR_NO_ID;
5eaef520 990 else
991 value = htonl(id);
7f426981 992 }
5eaef520 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));
7f426981 998 }
5eaef520 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;
7f426981 1016 }
1017 }
1018
5eaef520 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;
7f426981 1034}
1035
1036
1037/* setup_ahal():
1038 */
1039
5eaef520 1040int setup_ahal(struct query *q, char **argv, client *cl)
7f426981 1041{
5eaef520 1042 EXEC SQL BEGIN DECLARE SECTION;
1043 char *name;
1044 int cnt;
1045 EXEC SQL END DECLARE SECTION;
1046 char *p;
1047
84f3d463 1048 name = argv[0];
1049 if (!hostname_check(argv[0]))
5eaef520 1050 return MR_BAD_CHAR;
7f426981 1051
5eaef520 1052 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine WHERE
ad06a10e 1053 name = UPPER(:name);
5eaef520 1054 if (dbms_errno)
1055 return mr_errcode;
1056 if (cnt > 0)
1057 return MR_EXISTS;
7f426981 1058
5eaef520 1059 return MR_SUCCESS;
7f426981 1060}
84f3d463 1061
2884200f 1062/* setup_uhha(): Check characters in hwaddr, and make sure it's not
1063 * a duplicate.
1064 */
1065int 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 */
1098int setup_aprn(struct query *q, char **argv, client *cl)
1099{
1a9a0a59 1100 int best = -1, row;
2884200f 1101 char *p;
1102 EXEC SQL BEGIN DECLARE SECTION;
1103 int mid, usage, count;
1a9a0a59 1104 char types[STRINGS_STRING_SIZE], *hwaddr, *name, *duplexname, *oldname;
2884200f 1105 EXEC SQL END DECLARE SECTION;
1106
1a9a0a59 1107 /* Check for aprn or uprn. */
1108 if (q->type == APPEND)
1109 row = 0;
1110 else
1111 row = 1;
1112
1113 name = argv[PRN_NAME + row];
1114 duplexname = argv[PRN_DUPLEXNAME + row];
1115 oldname = argv[0];
1116
2884200f 1117 if (!*name)
1118 return MR_BAD_CHAR;
1119 else
1120 {
1a9a0a59 1121 if (q->type == APPEND)
1122 {
1123 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1124 WHERE name = :name OR duplexname = :name;
1125 }
1126 else
1127 {
1128 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1129 WHERE ( name = :name OR duplexname = :name )
1130 AND name != :oldname;
1131 }
2884200f 1132 if (dbms_errno)
1133 return mr_errcode;
1134 if (count)
1135 return MR_NOT_UNIQUE;
1136 }
1137
1a9a0a59 1138 if (*duplexname)
2884200f 1139 {
1a9a0a59 1140 if (q->type == APPEND)
1141 {
1142 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1143 WHERE name = :duplexname OR duplexname = :duplexname;
1144 }
1145 else
1146 {
1147 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1148 WHERE ( name = :duplexname OR duplexname = :duplexname )
1149 AND name != :oldname;
1150 }
1151
2884200f 1152 if (dbms_errno)
1153 return mr_errcode;
1154 if (count)
1155 return MR_NOT_UNIQUE;
1156 }
1157
1a9a0a59 1158 if (!strcmp(name, duplexname))
1159 return MR_NOT_UNIQUE;
1160
1161 mid = *(int *)argv[PRN_RM + row];
1162 if (mid == -1)
2884200f 1163 {
1164 EXEC SQL DECLARE csr_rm CURSOR FOR
1a9a0a59 1165 SELECT ps.mach_id, s.string FROM printservers ps, strings s
b3e26217 1166 WHERE ps.mach_id IN
1167 ( SELECT mach_id FROM serverhosts WHERE service = 'PRINT'
1168 AND enable = 1 )
1169 AND ps.printer_types = s.string_id;
2884200f 1170 if (dbms_errno)
1171 return mr_errcode;
1172 EXEC SQL OPEN csr_rm;
1173 if (dbms_errno)
1174 return mr_errcode;
1175
1176 while (1)
1177 {
1a9a0a59 1178 EXEC SQL FETCH csr_rm INTO :mid, :types;
2884200f 1179 if (sqlca.sqlcode)
1180 break;
1181
2884200f 1182 for (p = strtok(types, ", "); p; p = strtok(NULL, ", "))
1183 {
1a9a0a59 1184 if (!strcasecmp(argv[PRN_TYPE + row], p))
2884200f 1185 {
1a9a0a59 1186 EXEC SQL SELECT COUNT(name) INTO :usage
cc0ea77e 1187 FROM printers WHERE rm = :mid;
1a9a0a59 1188
119230bb 1189 if (best < 0 || usage < best)
1a9a0a59 1190 {
1191 best = usage;
1192 *(int *)argv[PRN_RM + row] = mid;
1193 break;
1194 }
2884200f 1195 }
1196 }
1197 }
1198 EXEC SQL CLOSE csr_rm;
1199 if (dbms_errno)
1200 return mr_errcode;
1201
1202 if (best == -1)
1203 return MR_SERVICE;
1204 }
2681538c 1205 else
1206 {
1207 EXEC SQL SELECT mach_id INTO :mid FROM printservers
1208 WHERE mach_id = :mid;
1209 if (sqlca.sqlcode)
1210 return MR_SERVICE;
1211 }
2884200f 1212
1213 return MR_SUCCESS;
1214}
1215
1a9a0a59 1216int setup_dpsv(struct query *q, char **argv, client *cl)
1217{
1218 int id;
1219 EXEC SQL BEGIN DECLARE SECTION;
1220 int cnt;
1221 EXEC SQL END DECLARE SECTION;
1222
1223 id = *(int *)argv[0];
1224
1225 EXEC SQL SELECT COUNT(rm) INTO :cnt FROM printers
1226 WHERE rm = :id;
1227 if (cnt > 0)
1228 return MR_IN_USE;
1229
1230 return MR_SUCCESS;
1231}
1232
84f3d463 1233/* hostname_check()
9e252e6f 1234 * validate the rfc1035/rfc1123-ness of a hostname
84f3d463 1235 */
1236
1237int hostname_check(char *name)
1238{
1239 char *p;
1240 int count;
1241
9e252e6f 1242 /* Sanity check name: must contain only letters, numerals, and
1243 * hyphen, and not start or end with a hyphen. Also make sure no
16affa56 1244 * label (the thing the .s seperate) is longer than 63 characters,
1245 * or empty.
84f3d463 1246 */
1247
9e252e6f 1248 for (p = name, count = 0; *p; p++)
84f3d463 1249 {
1250 count++;
1251 if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1252 (*p == '-' && p[1] == '.'))
1253 return 0;
1254 if (*p == '.')
16affa56 1255 {
1256 if (count == 1)
1257 return 0;
1258 count = 0;
1259 }
84f3d463 1260 if (count == 64)
1261 return 0;
1262 }
1263 if (*(p - 1) == '-')
1264 return 0;
1265 return 1;
1266}
9e252e6f 1267
17f585b5 1268int hostinfo_check(char *info, int num)
9e252e6f 1269{
1270 char *p;
1271
1272 if (!*info)
1273 return 1;
1274
17f585b5 1275 /* Sanity check host hostinfo: must start with a letter (or number
1276 * if num is true), contain only letters, numerals, and hyphen, and
1277 * not end with a hyphen.
9e252e6f 1278 */
1279
17f585b5 1280 if (!isalpha(*info) && (!num || !isdigit(*info)))
9e252e6f 1281 return 0;
1282 for (p = info; *p; p++)
1283 {
1284 if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1285 (*p == '-' && p[1] == '.'))
1286 return 0;
1287 }
1288 if (!isalnum(*(p - 1)))
1289 return 1;
1290}
This page took 0.490301 seconds and 5 git commands to generate.