]> andersk Git - moira.git/blob - server/qsupport.qc
Initial revision
[moira.git] / server / qsupport.qc
1 /*
2  *      $Source$
3  *      $Author$
4  *      $Header$
5  *
6  *      Copyright (C) 1987 by the Massachusetts Institute of Technology
7  *
8  *      $Log$
9  *      Revision 1.1  1987-07-29 15:13:57  wesommer
10  *      Initial revision
11  *
12  */
13
14 #ifndef lint
15 static char *rcsid_qsupport_qc = "$Header$";
16 #endif lint
17
18 #include "query.h"
19 #include "sms_server.h"
20 #include <ctype.h>
21
22 #define SMS_SUCCESS 0
23
24 extern char *whoami;
25
26 /* Specialized Access Routines */
27
28 /**
29  ** access_user - verify that client name equals specified login name
30  **
31  ** Used by: update_user_shell
32  **          update_finger_by_login
33  **
34  **  - since field validation routines are called first, a users_id is
35  **    now in argv[0] instead of the login name.  Therefore, we must 
36  **    convert the client name to a users_id.
37  **/
38
39 access_user(q, argv, cl)
40     struct query *q;
41     char *argv[];
42     client *cl;
43 ##{
44     register struct krbname *krb;
45 ##  int client_id;
46 ##  char *client_name;
47 ##  int rowcount;
48
49     client_name = cl->kname.name;
50 ##  repeat retrieve (client_id = users.users_id) 
51 ##         where users.login = @client_name
52 ##  inquire_equel (rowcount = "rowcount")
53     if (rowcount != 1) return(SMS_PERM);
54     if (client_id != *(int *)argv[0]) return(SMS_PERM);
55
56     return(SMS_SUCCESS);
57 ##}
58     
59 /**
60  ** access_list - check access for adding or deleting list members
61  **
62  ** Inputs: argv[0] - list_id
63  **         cl->krb.name - client name
64  **
65  ** - check that client is a member of the access control list
66  ** - OR, if q->shortname == {amtl | dfml} and
67  **       if list.flags & LF_PUBLIC, allow access if client = member
68  **
69  **/ 
70
71 access_list(q, argv, cl)
72     struct query *q;
73     char *argv[];
74     client *cl;
75 ##{
76 ##  int list_id;
77 ##  int acl_id;
78 ##  int flags;
79     int member_id;
80     char *client_type;
81     int client_id;
82     int status;
83     int exists;
84
85     list_id = *(int *)argv[0];
86 ##  repeat retrieve (acl_id = list.#acl_id, flags = list.#flags) 
87 ##         where list.#list_id = @list_id
88
89     /* parse client structure */
90     status = get_client(cl, &client_type, &client_id);
91     if (status != SMS_SUCCESS) return(status);
92
93     /* if amtl or dmfl and list is public allow client to add or delete self */
94     if (!bcmp("amtl", q->shortname, 4) || !bcmp("dmfl", q->shortname, 4)) {
95         if ((flags & LF_PUBLIC) && !bcmp("USER", argv[1], 4)) {
96             member_id = *(int *)argv[2];
97             if (member_id == client_id) return(SMS_SUCCESS);
98         }
99     }
100
101     /* check for client in access control list */
102     exists = find_member(acl_id, client_type, client_id, 0);
103     if (!exists) return(SMS_PERM);
104
105     return(SMS_SUCCESS);
106 ##}
107 \f
108 /**
109  ** Setup routine for add_user
110  **
111  ** Inputs: argv[0] - login
112  **         argv[1] - uid
113  **
114  ** Description:
115  **
116  ** - if argv[1] == "#" then set argv[1] = next(uid)
117  ** - if argv[0] == "#" then set argv[0] = "#<uid>"
118  **
119  **/
120
121 setup_add_user(q, argv, cl, access_check)
122     struct query *q;
123     register char *argv[];
124     client *cl;
125     int access_check;
126 ##{
127 ##  int nuid;
128 ##  int exists;
129
130     if (access_check) return(SMS_SUCCESS);
131
132     if (!bcmp(argv[1], "#", 2)) {
133 ##      range of u is users
134 ##      range of v is values
135 ##      repeat retrieve (nuid = v.value) where v.name = "uid"
136         exists = 1;
137         while (exists) {
138             nuid++;
139 ##          repeat retrieve (exists = any(u.#uid where u.#uid = @nuid))
140         }
141 ##      repeat replace v (value = @nuid) where v.name = "uid"
142         sprintf(argv[1], "%d", nuid);
143     }
144
145     if (!bcmp(argv[0], "#", 2)) {
146         sprintf(argv[0], "#%s", argv[1]);
147     }
148
149     return(SMS_SUCCESS);
150 ##}
151
152 /**
153  ** Setup routine for add_group
154  **
155  ** Inputs: none
156  **
157  ** Description: allocate next gid and store in values table
158  **
159  **/
160
161 setup_add_group(q, argv, cl, access_check)
162     struct query *q;
163     char *argv[];
164     client *cl;
165     int access_check;
166 ##{
167 ##  int ngid;
168 ##  int exists;
169
170     if (access_check) return(SMS_SUCCESS);
171
172 ##  range of g is groups
173 ##  range of v is values
174 ##  repeat retrieve (ngid = v.value) where v.name = "gid"
175     exists = 1;
176     while (exists) {
177         ngid++;
178 ##      repeat retrieve (exists = any(g.#gid where g.#gid = @ngid))
179     }
180
181 ##  repeat replace v (value = @ngid) where v.name = "gid"
182     return(SMS_SUCCESS);
183 ##}
184 \f
185 /* Followup Routines */
186
187 set_user_modtime(q, argv)
188     struct query *q;
189     char *argv[];
190 ##{
191 ##  char *login;
192
193     login = argv[0];
194 ##  repeat replace u (modtime = "now") where u.#login = @login
195     return(SMS_SUCCESS);
196 ##}
197
198 set_user_modtime_by_id(q, argv)
199     struct query *q;
200     char *argv[];
201 ##{
202 ##  int users_id;
203
204     users_id = *(int *)argv[0];
205 ##  repeat replace users (modtime = "now") where users.#users_id = @users_id
206     return(SMS_SUCCESS);
207 ##}
208
209 set_list_modtime(q, argv)
210     struct query *q;
211     char *argv[];
212 ##{
213 ##  char *list_name;
214
215     list_name = argv[0];
216 ##  repeat replace list (modtime = "now") where list.name = @list_name
217     return(SMS_SUCCESS);
218 ##}
219
220 set_list_modtime_by_id(q, argv)
221     struct query *q;
222     char *argv[];
223 ##{
224 ##  int list_id;
225
226     list_id = *(int *)argv[0];
227 ##  repeat replace list (modtime = "now") where list.#list_id = @list_id
228     return(SMS_SUCCESS);
229 ##}
230
231 set_finger_modtime(q, argv)
232     struct query *q;
233     char *argv[];
234 ##{
235 ##  int users_id;
236
237     users_id = *(int *)argv[0];
238 ##  repeat replace f (modtime = "now") where f.#users_id = @users_id
239     return(SMS_SUCCESS);
240 ##}
241
242 /**
243  ** delete_list_members - called after the delete_list query to clean up
244  **                       members table.
245  **
246  ** Inputs: argv[0] - list_id
247  **
248  ** Description:
249  **   - foreach string member: decr string refc; ifzero, delete string
250  **   - delete all members entries for this list_id
251  **
252  **/
253
254 delete_list_members(q, argv)
255     struct query *q;
256     register char *argv[];
257 ##{
258 ##  int list_id;
259 ##  int string_id;
260 ##  int refc;
261 ##  int rowcount;
262     struct save_queue *sq;
263     struct save_queue *sq_create();
264
265     list_id = *(int *)argv[0];
266     sq = sq_create();
267
268 ##  range of m is members
269 ##  repeat retrieve (string_id = m.member_id)
270 ##         where m.#list_id = @list_id and m.member_type = "STRING"
271 ##  {
272          sq_save_data(sq, string_id);
273 ##  }
274
275     while (sq_get_data(sq, &string_id)) {
276 ##      range of s is strings
277 ##      repeat retrieve (refc = s.#refc) where s.#string_id = @string_id
278 ##      inquire_equel (rowcount = "rowcount")
279         if (rowcount == 0) continue;
280         if (--refc == 0) {
281 ##          repeat delete s where s.#string_id = @string_id
282         } else {
283 ##          repeat replace s (#refc = @refc) where s.#string_id = @string_id
284         }
285     }
286     sq_destroy(sq);
287
288 ##  repeat delete m where m.#list_id = @list_id
289
290     return(SMS_SUCCESS);
291 ##}
292
293 /**
294  ** grvd_support - Support routine for get_rvd_servers query
295  **
296  ** Inputs:
297  **    q     - grvd query structure
298  **    sq    - save_queue struture: contains list of {machine, oper_acl_id,
299  **            admin_acl_id, shutdown_acl_id} records.
300  **    v     - validate structure (not used)
301  **    action - action routine
302  **    actarg - action routine argument
303  **
304  ** Description:
305  **   - translate acl_ids to list names
306  **
307  **/
308
309 grvd_support(q, sq, v, action, actarg)
310     struct query *q;
311     struct save_queue *sq;
312     struct validate *v;
313     int (*action)();
314     int actarg;
315 ##{
316     char **argv;
317     char *targv[4];
318 ##  char oper[33];
319 ##  char admin[33];
320 ##  char shutdown[33];
321 ##  int list_id;
322
323     targv[1] = oper;
324     targv[2] = admin;
325     targv[3] = shutdown;
326
327 ##  range of l is list
328
329     while (sq_get_data(sq, &argv)) {
330         sscanf(argv[1], "%d", &list_id);
331 ##      repeat retrieve (oper = l.name) where l.#list_id = @list_id
332         sscanf(argv[2], "%d", &list_id);
333 ##      repeat retrieve (admin = l.name) where l.#list_id = @list_id
334         sscanf(argv[3], "%d", &list_id);
335 ##      repeat retrieve (shutdown = l.name) where l.#list_id = @list_id
336         
337         targv[0] = argv[0];
338         (*action)(4, targv, actarg);
339         free(argv[0]);
340         free(argv[1]);
341         free(argv[2]);
342         free(argv[3]);
343     }
344
345     sq_destroy(sq);
346     return(SMS_SUCCESS);
347 ##}
348
349 /**
350  ** set_next_object_id - set next object id in values table
351  **
352  ** Inputs: object - object name in values table
353  **
354  ** - called before an APPEND operation to set the next object id to
355  **   be used for the new record
356  **
357  **/
358
359 set_next_object_id(object)
360     char *object;
361 ##{
362 ##  char *name;
363 ##  int id;
364
365     name = object;
366 ##  range of v is values
367 ##  repeat retrieve (id = v.value) where v.#name = @name
368     id++;
369 ##  repeat replace v (value = @id) where v.#name = @name
370     return(SMS_SUCCESS);
371 ##}
372
373 \f
374 /**
375  ** add_locker - special query routine for creating a user locker
376  **
377  ** Inputs:
378  **   argv[0] - users_id
379  **   argv[1] - machine_id
380  **   argv[2] - device
381  **   argv[3] - initial quota
382  ** 
383  ** Description:
384  **   - get prefix directory (dir) for mount point on specified machine/device
385  **   - create filesys entry (label=<login>, type=NFS, machine=<machine>,
386  **     mount=<dir>/<login>, access=w, acl=dbadmin)
387  **   - increment allocated in nfsphys by quota
388  **   - create nfsquota entry
389  **
390  ** Errors:
391  **   - SMS_NFSPHYS - machine/device does not exist in nfsphys
392  **   - SMS_FILESYS_EXISTS - file system already exists
393  ** 
394  **/
395
396 add_locker(q, argv)
397     register struct query *q;
398     char *argv[];
399 ##{
400 ##  int users_id;
401 ##  int mach_id;
402 ##  char *device;
403 ##  int quota;
404 ##  int rowcount;
405 ##  char *login;
406 ##  char dir[32];
407 ##  int allocated;
408 ##  char locker[64];
409 ##  char mount[64];
410 ##  int user_acl;
411
412     /* copy arguments */
413     users_id = *(int *)argv[0];
414     mach_id = *(int *)argv[1];
415     device = argv[2];
416     sscanf(argv[3], "%d", &quota);
417
418 ##  range of u is users
419 ##  range of f is filesys
420 ##  range of np is nfsphys
421
422     /* get login name */
423 ##  repeat retrieve (login = u.#login) where u.#users_id = @users_id
424
425     /* get user's acl id */
426 ##  repeat retrieve (user_acl = list.list_id) where list.name = @login
427
428     /* get filesystem directory prefix; give error if machine/device
429        pair not in nfsphys table */
430 ##  repeat retrieve (dir = np.#dir, allocated = np.#allocated) 
431 ##         where np.#mach_id = @mach_id and np.#device = device
432 ##  inquire_equel (rowcount = "rowcount")
433     if (rowcount == 0) return(SMS_NFSPHYS);
434
435     /* make sure a filesys with user's name does not already exist */
436 ##  repeat retrieve (rowcount = any(f.label where f.label = @login))
437     if (rowcount != 0) return(SMS_FILESYS_EXISTS);
438
439     /* create a new filesys */
440     sprintf(locker, "%s/%s", dir, login);
441     sprintf(mount, "/mit/%s", login);
442 ##  repeat append filesys 
443 ##             (#users_id = @users_id, type = "NFS", #mach_id = @mach_id,
444 ##              name = @locker, access = "w", order = 1, #mount = @mount,
445 ##              acl_id = @user_acl)
446
447     /* increment usage count in nfsphys table */
448     allocated += quota;
449 ##  replace np (#allocated = allocated) 
450 ##          where np.#mach_id = mach_id and np.#device = device
451
452     /* create nfsquota entry */
453 ##  append nfsquota (#users_id = users_id, #mach_id = mach_id,
454 ##                   device = #device, #quota = quota)
455
456     return(SMS_SUCCESS);
457 ##}
458 \f
459 /* Validation Routines */
460
461 validate_row(q, argv, v)
462     register struct query *q;
463     char *argv[];
464     register struct validate *v;
465 ##{
466 ##  char *rvar;
467 ##  char *table;
468 ##  char *name;
469 ##  char qual[128];
470 ##  int rowcount;
471
472     /* build where clause */
473     build_qual(v->qual, v->argc, argv, qual);
474
475     /* setup ingres variables */
476     rvar = q->rvar;
477     table = q->rtable;
478     name = v->field;
479
480     /* tell the logfile what we're doing */
481     com_err(whoami, 0, "validating row");
482     com_err(whoami, 0, qual);
483
484     /* look for the record */
485 ##  range of rvar is table
486 ##  retrieve (rowcount = count(rvar.name where qual))
487     com_err(whoami, 0, "row validated");
488     if (rowcount == 0) return(SMS_NO_MATCH);
489     if (rowcount > 1) return(SMS_NOT_UNIQUE);
490     return(SMS_EXISTS);
491 ##}
492
493 validate_fields(q, argv, vo, n)
494     struct query *q;
495     register char *argv[];
496     register struct valobj *vo;
497     register int n;
498 {
499     register int status;
500     char buf[64];
501
502     while (--n >= 0) {
503         switch (vo->type) {
504         case V_NAME:
505             sprintf(buf, "validating %s in %s: %s", 
506                     vo->namefield, vo->table, argv[vo->index]);
507             com_err(whoami, 0, buf);
508             status = validate_name(argv, vo);
509             break;
510
511         case V_ID:
512             sprintf(buf, "validating %s in %s: %s", 
513                     vo->idfield, vo->table, argv[vo->index]);
514             com_err(whoami, 0, buf);
515             status = validate_id(argv, vo);
516             break;
517
518         case V_TYPE:
519             sprintf(buf, "validating %s type: %s",
520                     vo->table, argv[vo->index]);
521             com_err(whoami, 0, buf);
522             status = validate_type(argv, vo);
523             break;
524
525         case V_TYPEDATA:
526             sprintf(buf, "validating type-specific data: %s",
527                     argv[vo->index]);
528             com_err(whoami, 0, buf);
529             status = validate_typedata(q, argv, vo);
530             break;
531
532         case V_FOLLOWUP:
533             status = SMS_EXISTS;
534             break;
535
536         }
537
538         if (status != SMS_EXISTS) return(status);
539         vo++;
540     }
541
542     return(SMS_SUCCESS);
543 }
544
545 validate_id(argv, vo)
546     char *argv[];
547     register struct valobj *vo;
548 ##{
549 ##  char *name;
550 ##  char *table;
551 ##  char *namefield;
552 ##  char *idfield;
553 ##  int id;
554 ##  int rowcount;
555
556     name = argv[vo->index];
557     table = vo->table;
558     namefield = vo->namefield;
559     idfield = vo->idfield;
560 ##  retrieve (id = table.idfield) where table.namefield = name
561 ##  inquire_equel (rowcount = "rowcount")
562     if (rowcount != 1) return(vo->error);
563     *(int *)argv[vo->index] = id;
564     return(SMS_EXISTS);
565 ##}
566
567 validate_name(argv, vo)
568     char *argv[];
569     register struct valobj *vo;
570 ##{
571 ##  char *name;
572 ##  char *table;
573 ##  char *namefield;
574 ##  int rowcount;
575
576     name = argv[vo->index];
577     table = vo->table;
578     namefield = vo->namefield;
579 ##  retrieve (rowcount = countu(table.namefield 
580 ##            where table.namefield = name))
581     return ((rowcount == 1) ? SMS_EXISTS : vo->error);
582 ##}
583
584 validate_type(argv, vo)
585     char *argv[];
586     register struct valobj *vo;
587 ##{
588 ##  char *typename;
589 ##  char *value;
590 ##  int rowcount;
591     register char *c;
592
593     typename = vo->table;
594     value = argv[vo->index];
595
596     /* uppercase type fields */
597     for (c = value; *c; c++) if (islower(*c)) *c = toupper(*c);
598
599 ##  range of a is alias
600 ##  repeat retrieve (rowcount = count(a.trans where a.name = @typename and
601 ##                                    a.type = "TYPE" and
602 ##                                    a.trans = @value))
603     return ((rowcount == 1) ? SMS_EXISTS : vo->error);
604 ##}
605
606 /* validate member or type-specific data field */
607
608 validate_typedata(q, argv, vo)
609     register struct query *q;
610     register char *argv[];
611     register struct valobj *vo;
612 ##{
613 ##  char *name;
614 ##  char *field_type;
615 ##  char data_type[17];
616 ##  int id;
617 ##  int refc;
618 ##  int rowcount;
619
620     /* get named object */
621     name = argv[vo->index];
622
623     /* get field type string (known to be at index-1) */
624     field_type = argv[vo->index-1];
625
626     /* get corresponding data type associated with field type name */
627 ##  repeat retrieve (data_type = alias.trans) 
628 ##         where alias.#name = @field_type and alias.type = "TYPEDATA"
629 ##  inquire_equel (rowcount = "rowcount")
630     if (rowcount != 1) return(SMS_TYPE);
631
632     /* now retrieve the record id corresponding to the named object */
633
634     if (!strcmp(data_type, "user")) {
635         /* USER */
636 ##      repeat retrieve (id = users.users_id) where users.login = @name
637 ##      inquire_equel (rowcount = "rowcount")
638         if (rowcount != 1) return(SMS_USER);
639
640     } else if (!strcmp(data_type, "list")) {
641         /* LIST */
642 ##      repeat retrieve (id = list.list_id) where list.#name = @name
643 ##      inquire_equel (rowcount = "rowcount")
644         if (rowcount != 1) return(SMS_LIST);
645
646     } else if (!strcmp(data_type, "machine")) {
647         /* MACHINE */
648 ##      repeat retrieve (id = machine.mach_id) where machine.#name = @name
649 ##      inquire_equel (rowcount = "rowcount")
650         if (rowcount != 1) return(SMS_MACHINE);
651
652     } else if (!strcmp(data_type, "string")) {
653         /* STRING */
654 ##      range of s is strings
655 ##      repeat retrieve (id = s.string_id, refc = s.#refc) 
656 ##             where s.string = @name
657 ##      inquire_equel (rowcount = "rowcount")
658         if (rowcount == 0) {
659             if (q->type != APPEND) return(SMS_STRING);
660 ##          range of v is values
661 ##          retrieve (id = v.value) where v.#name = "strings_id"
662             id++;
663 ##          replace v (value = id) where v.#name = "strings_id"
664 ##          append to strings (string_id = id, string = name, #refc = 1)
665         } else if (rowcount == 1) {
666             if (q->type == APPEND || q->type == DELETE) {
667                 refc += (q->type == APPEND) ? 1 : -1;
668                 if (refc > 0) {
669 ##                  replace s (#refc = refc) where s.string_id = id
670                 } else {
671 ##                  delete s where s.string_id = id
672                 }
673             }
674         }
675     } else {
676         return(SMS_TYPE);
677     }
678
679     /* now set value in argv */
680     *(int *)argv[vo->index] = id;
681     
682     return (SMS_EXISTS);
683 ##}
684
685 \f
686 translate_ids(q, sq, v, action, actarg)
687     register struct query *q;
688     register struct save_queue *sq;
689     register struct validate *v;
690     register int (*action)();
691     int actarg;
692 ##{
693 ##  char *name;
694 ##  char *field_type;
695 ##  char data_type[17];
696 ##  int id;
697 ##  int rowcount;
698     register int i;
699     struct valobj *vo;
700     char **argv;
701
702     for (i = 0; i < v->objcnt; i++) {
703         vo = &v->valobj[i];
704         if (vo->type == V_FOLLOWUP) break;
705     }
706
707     /* for each row */
708     while (sq_get_data(sq, &argv)) {
709
710         /* get object id */
711         i = vo->index;
712         sscanf(argv[i], "%d", &id);
713         free(argv[i]);
714         name = (char *)malloc(129);
715         argv[i] = name;
716
717         /* get field type string (known to be at index-1) */
718         field_type = argv[vo->index-1];
719
720         /* get corresponding data type associated with field type name */
721 ##      repeat retrieve (data_type = alias.trans) 
722 ##             where alias.#name = @field_type and alias.type = "TYPEDATA"
723 ##      inquire_equel (rowcount = "rowcount")
724         if (rowcount != 1) {
725             sprintf(name, "%d", id);
726             (*action)(q->vcnt, argv, actarg);
727             continue;
728         }
729
730         /* retrieve object name */
731
732         if (!strcmp(data_type, "user")) {
733             /* USER */
734 ##          repeat retrieve (name = users.login) where users.users_id = @id
735 ##          inquire_equel (rowcount = "rowcount")
736
737         } else if (!strcmp(data_type, "list")) {
738             /* LIST */
739 ##          repeat retrieve (name = list.#name) where list.list_id = @id
740 ##          inquire_equel (rowcount = "rowcount")
741
742         } else if (!strcmp(data_type, "machine")) {
743             /* MACHINE */
744 ##          repeat retrieve (name = machine.#name) where machine.mach_id = @id
745 ##          inquire_equel (rowcount = "rowcount")
746
747         } else if (!strcmp(data_type, "string")) {
748             /* STRING */
749 ##          repeat retrieve (name = strings.string) 
750 ##                 where strings.string_id = @id
751 ##          inquire_equel (rowcount = "rowcount")
752
753         } else {
754             rowcount = 0;
755         }
756
757         /* if there wasn't a corresponding object name, then use the id */
758         if (rowcount != 1) sprintf(name, "%d", id);
759
760         /* send the data */
761         (*action)(q->vcnt, argv, actarg);
762
763         /* free saved data */
764         for (i = 0; i < q->vcnt; i++) 
765             free(argv[i]);
766         free(argv);
767     }
768
769     sq_destroy(sq);
770     return (SMS_SUCCESS);
771 ##}
772 \f
773 /*
774  * Local Variables:
775  * mode: c
776  * c-indent-level: 4
777  * c-continued-statement-offset: 4
778  * c-brace-offset: -4
779  * c-argdecl-indent: 4
780  * c-label-offset: -4
781  * End:
782  */
This page took 0.249366 seconds and 5 git commands to generate.