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