source: trunk/athena/bin/discuss/server/coreutil.c @ 2750

Revision 2750, 17.1 KB checked in by srz, 35 years ago (diff)
Hmmm. Should not exceed array bounds, should we?
Line 
1/*
2 *
3 *      Copyright (C) 1988, 1989 by the Massachusetts Institute of Technology
4 *      Developed by the MIT Student Information Processing Board (SIPB).
5 *      For copying information, see the file mit-copyright.h in this release.
6 *
7 */
8/*
9 *      $Source: /afs/dev.mit.edu/source/repository/athena/bin/discuss/server/coreutil.c,v $
10 *      $Header: /afs/dev.mit.edu/source/repository/athena/bin/discuss/server/coreutil.c,v 1.22 1990-02-24 20:05:09 srz Exp $
11 *
12 *
13 * coreutil.c  -- These contain lower-layer, utility type routines to
14 *                be used by core.  These include things to handle the
15 *                in-memory superblock, and to open & close meetings.
16 *
17 *      $Log: not supported by cvs2svn $
18 * Revision 1.21  90/02/24  18:56:30  srz
19 * Changed read_trn to return the signature (if it exists), and changed
20 * mtg_znotify to handle the signature if it exists.
21 *
22 * Revision 1.20  89/09/01  11:54:13  srz
23 * Defined use_zephyr variable, even when ZEPHYR is not defined.
24 *
25 * Revision 1.19  89/09/01  11:51:18  srz
26 * Fixed memory leak, and cut connection between super_chairman and access.
27 *
28 * Revision 1.18  89/08/09  22:39:43  srz
29 * Added meeting forwarding.
30 *
31 * Revision 1.17  89/06/03  00:42:34  srz
32 * Added standard copyright notice.
33 *
34 * Revision 1.16  89/06/03  00:36:43  srz
35 * Include file fixups, more efficient Zephyr service.
36 *
37 * Revision 1.15  88/10/13  01:26:29  discuss
38 * Fixed Zephyr stuff.  Can you say, "Insufficient documentation?"  -srz
39 *
40 * Revision 1.14  88/10/08  03:28:49  srz
41 * Attempt at fixing Zephyr (doesn't work).
42 *
43 * Revision 1.13  88/10/08  01:28:26  srz
44 * Changes for new expunge.  Fix to Zephyr stuff.
45 *
46 * Revision 1.12  88/09/23  17:07:33  raeburn
47 * Changed type names in accordance with acl.h.  Included include/internal.h.
48 *
49 * Revision 1.11  88/03/06  19:53:28  srz
50 * Reversed order of checking magic number and version, so that
51 * INCONSISTENT is returned instead of NEW_VERSION when that
52 * is trully the case.
53 *
54 * Revision 1.10  88/01/05  01:37:54  srz
55 * Really ifdef'd zephyr.
56 *
57 * Revision 1.9  88/01/05  01:08:02  rfrench
58 * #ifdef'd ZEPHYR stuff
59 *
60 * Revision 1.8  87/08/22  18:12:30  rfrench
61 * Added Zephyr notifications
62 *
63 * Revision 1.7  87/03/25  15:04:31  srz
64 * toma change:  Expanded has_mtg_access to take more modes as arguments
65 *
66 * Revision 1.6  87/03/17  02:24:10  srz
67 * Added expunging.  An ACL change will require meeting to be reopened, in
68 * case an expunge is taking place.  Also added has_privs, which allows
69 * wheel access for programs that are linked in.
70 *
71 * Revision 1.5  87/03/11  18:00:27  srz
72 * Made sure that write's were error checked.
73 *
74 * Revision 1.4  87/02/04  15:48:18  srz
75 * When there is a choice between making lint happy or cc happy, I tend
76 * to prefer 'cc'.  uid_t is not in 4.2 BSD.
77 *
78 * Revision 1.3  86/11/22  06:25:42  spook
79 * Changed to make lint happy.
80 *
81 * Revision 1.2  86/11/16  06:05:37  wesommer
82 * Changed open_mtg to stat(2) the acl file before assuming that it's
83 * up to date, and revert the acl from there if the in-core version
84 * is stale.
85 *
86 */
87
88#ifndef lint
89#ifdef __STDC__
90const
91#endif
92static char rcsid_coreutil_c[] =
93    "$Header: /afs/dev.mit.edu/source/repository/athena/bin/discuss/server/coreutil.c,v 1.22 1990-02-24 20:05:09 srz Exp $";
94#endif /* lint */
95
96#include <discuss/types.h>
97#include <discuss/dsc_et.h>
98#include "atom.h"
99#include "mtg.h"
100#include <discuss/tfile.h>
101#include <discuss/acl.h>
102#include "internal.h"
103#include "ansi.h"
104#ifdef ZEPHYR
105#include <zephyr/zephyr.h>
106#endif ZEPHYR
107#include <errno.h>
108#include <sys/types.h>
109#include <netdb.h>
110#include <sys/file.h>
111#include <sys/stat.h>
112#include <strings.h>
113
114#define NULL 0
115
116/* global variables */
117char current_mtg [256] = "";    /* meeting that's opened */
118int u_trn_f,u_control_f,u_acl_f; /* UNIX file descriptors */
119bool nuclear = FALSE;           /* Using atomic reads/writes */
120afile a_control_f = NULL;       /* radioactive file descriptor */
121tfile abort_file = NULL;        /* close this on abort */
122bool  read_lock = FALSE;        /* have lock on u_control_f */
123dsc_acl   *mtg_acl = NULL;      /* current mtg acl */
124int     last_acl_mod;           /* last mod to ACL */
125mtg_super super;
126char *super_chairman;
127char *super_long_name;
128int has_privs = 0;              /* Has privileges (linked) */
129int no_nuke = 0;                /* Don't be atomic (linked) */
130#ifdef ZEPHYR
131int use_zephyr = 1;             /* Actually do use Zephyr. */
132#else
133int use_zephyr = 0;
134#endif
135
136
137/* EXTERNAL */
138extern char *malloc();
139extern off_t lseek();
140extern int errno;
141extern char rpc_caller [];
142
143/*
144 *
145 * new_string (s)  --   Routine to create a copy of the given string, using
146 *                      malloc.
147 *
148 */
149char *new_string (s)
150char *s;
151{
152     int len;
153     char *newstr;
154
155     len = strlen (s) + 1;
156     newstr = malloc ((unsigned)len);
157     (void) strcpy (newstr, s);
158     return (newstr);
159}
160
161/*
162 *
163 * open_mtg (mtg_name) -- Routine to open a meeting, if necessary.
164 *
165 */
166int open_mtg (mtg_name)
167char *mtg_name;
168{
169     char str[256];
170     int result;
171     int mtg_name_len;
172     trn_base tb;
173     int uid = (int)geteuid();
174     struct stat sb;
175
176     mtg_name_len = strlen (mtg_name);
177     if (mtg_name[0] != '/' || mtg_name_len == 0 || mtg_name_len > 168
178         || mtg_name [mtg_name_len-1] == '/') {
179          return (BAD_PATH);
180     }
181
182     /* Check for moved meeting */
183     (void) strcpy (str, mtg_name);
184     (void) strcat (str, "/forward");
185     if (!stat(str, &sb)) {
186          return(MTG_MOVED);
187     }
188
189     (void) strcpy (str, mtg_name);
190     (void) strcat (str, "/acl");
191
192     if (!strcmp (mtg_name, current_mtg)) {
193          /*
194           * is acl stale?
195           */
196          if (stat(str, &sb) >= 0)
197               if (sb.st_mtime <= last_acl_mod)
198                    return (0);                         /* that was easy */
199     }
200
201     if (current_mtg [0] != '\0') {             /* close previous meeting */
202          if (nuclear)
203               panic ("Nuclear flag error");    /* should never happen */
204          (void) close (u_trn_f);
205          (void) close (u_control_f);
206          current_mtg [0] = '\0';
207          acl_destroy(mtg_acl);
208     }
209
210     u_trn_f = u_control_f = u_acl_f = 0;
211
212     if ((u_acl_f = open(str, O_RDONLY, 0700)) < 0) {
213          if (errno == ENOENT)
214               result = NO_SUCH_MTG;
215          else if (errno == EACCES)
216               result = NO_ACCESS;
217          else
218               result = BAD_PATH;
219          goto punt;
220     }
221     if (!fis_owner (u_acl_f, uid)) {
222          result = NO_ACCESS;
223          goto punt;
224     }
225
226     mtg_acl = acl_read (u_acl_f);
227     (void) fstat(u_acl_f, &sb);
228     last_acl_mod = sb.st_mtime;
229     (void) close(u_acl_f);
230     u_acl_f = 0;
231
232     (void) strcpy (str, mtg_name);
233     (void) strcat (str, "/control");
234
235     if ((u_control_f = open(str, O_RDWR, 0700)) < 0) {
236          if (errno == ENOENT)
237               result = NO_SUCH_MTG;
238          else if (errno == EACCES)
239               result = NO_ACCESS;
240          else
241               result = BAD_PATH;
242          goto punt;
243     }
244
245     if (!fis_owner (u_control_f, uid)) {
246          result = NO_ACCESS;
247          goto punt;
248     }
249
250     (void) strcpy (str, mtg_name);
251     (void) strcat (str, "/transactions");
252     
253     if ((u_trn_f = open(str, O_RDWR, 0700)) < 0) {
254          if (errno == ENOENT)
255               result = NO_SUCH_MTG;
256          else if (errno == EACCES)
257               result = NO_ACCESS;
258          else
259               result = BAD_PATH;
260          goto punt;
261     }
262
263     if (!fis_owner (u_trn_f, uid)) {
264          result = NO_ACCESS;
265          goto punt;
266     }
267
268     read (u_trn_f, (char *) &tb, sizeof (trn_base));
269     if (tb.unique != TRN_BASE_UNIQUE) {
270          result = INCONSISTENT;
271          goto punt;
272     }
273
274     (void) strcpy (current_mtg, mtg_name);
275
276     return (0);
277
278 punt:
279     if (u_trn_f)
280             (void) close(u_trn_f);
281     if (u_control_f)
282             (void) close(u_control_f);
283     if (u_acl_f)
284             (void) close(u_acl_f);
285     acl_destroy(mtg_acl);
286     mtg_acl = NULL;
287     return (result);
288}
289
290
291int read_super()
292{
293     if (nuclear) {
294          aread (a_control_f, (char *) &super, sizeof(super), 0);
295     } else {
296             lseek (u_control_f, (long)0, 0);
297             read (u_control_f, (char *) &super, sizeof (super));
298     }
299
300     if (super.unique != MTG_SUPER_UNIQUE)
301          return (INCONSISTENT);
302
303     if (super.version != MTG_SUPER_1)
304          return (NEW_VERSION);
305
306     super_long_name = malloc ((unsigned)super.long_name_len);
307     super_chairman = malloc ((unsigned)super.chairman_len);
308
309     if (nuclear) {
310          aread (a_control_f, super_long_name, super.long_name_len, super.long_name_addr);
311          aread (a_control_f, super_chairman, super.chairman_len, super.chairman_addr);
312     } else {
313          lseek (u_control_f, (long)super.long_name_addr, 0);
314          read (u_control_f, super_long_name, super.long_name_len);
315          lseek (u_control_f, (long)super.chairman_addr, 0);
316          read (u_control_f, super_chairman, super.chairman_len);
317     }
318
319     return(0);
320}
321
322write_super ()
323{
324     int sc_len, sl_len;
325
326     sc_len = strlen (super_chairman)+1;
327     sl_len = strlen (super_long_name)+1;
328
329     if (sc_len != super.chairman_len || sl_len != super.long_name_len) {               /* reallocate things */
330          super.long_name_addr = sizeof (super);
331          super.long_name_len = sl_len;
332          super.chairman_addr = super.long_name_addr + super.long_name_len;
333          super.chairman_len = sc_len;
334     }
335
336     if (nuclear) {
337          awrite (a_control_f, (char *) &super, sizeof (super), 0);
338          awrite (a_control_f, super_long_name, super.long_name_len, super.long_name_addr);
339          awrite (a_control_f, super_chairman, super.chairman_len, super.chairman_addr);
340     } else {
341          lseek (u_control_f, (long)0, 0);
342          write (u_control_f, (char *)  &super, sizeof (super));
343          lseek (u_control_f, (long)super.long_name_addr, 0);
344          write (u_control_f, super_long_name, super.long_name_len);
345          lseek (u_control_f, (long)super.chairman_addr, 0);
346          write (u_control_f, super_chairman, super.chairman_len);
347     }
348
349     free (super_chairman);
350     super_chairman = NULL;
351     free (super_long_name);
352     super_long_name = NULL;
353     super.unique = 0;                                  /* prevent accidents */
354
355     return;
356}
357
358/*
359 *
360 * forget_super () -- Routine to dump superblock, like when we just read
361 *                    it.  This frees any alloc'd storage.
362 *
363 */
364forget_super()
365{
366     if (super_long_name != NULL)
367          free(super_long_name);
368     super_long_name = NULL;
369
370     if (super_chairman != NULL)
371          free(super_chairman);
372     super_chairman = NULL;
373     super.unique = 0;
374}
375
376/*
377 *
378 * start_read () --     This reserves the meeting for non-destructive reading.
379 *                      Simply does an flock.
380 *
381 */
382start_read()
383{
384     if (!no_nuke) {
385          if (flock (u_control_f, LOCK_SH) < 0)
386               panic ("Cannot share lock");
387          read_lock = TRUE;
388     }
389}
390
391/*
392 *
393 * finish_read () --    This frees up our reservation on the meeting.  This
394 *                      does the opposite of start_read.
395 *
396 */
397finish_read()
398{
399     if (!no_nuke) {
400          flock(u_control_f,LOCK_UN);
401          read_lock = 0;
402     }
403}
404
405/*
406 *
407 * chain_addr -- Returns address of given chain block.
408 *
409 */
410faddr chain_addr(trn)
411trn_nums trn;
412{
413     if (trn < super.lowest || trn > super.highest)
414          return (0);
415
416     return (super.chain_start + (trn-1) * sizeof (chain_blk));
417}
418
419int read_chain (trn, cb)
420trn_nums trn;
421chain_blk *cb;
422{
423     faddr cbaddr;
424
425     cbaddr = chain_addr (trn);
426     if (cbaddr == 0)
427          return (NO_SUCH_TRN);
428
429     if (nuclear)
430          aread (a_control_f, (char *) cb, sizeof (chain_blk), cbaddr);
431     else {
432          lseek (u_control_f, (long)cbaddr, 0);
433          read (u_control_f, (char *) cb, sizeof (chain_blk));
434     }
435
436     if (cb -> unique != CHAIN_BLK_UNIQUE || cb -> current != trn)
437          return (INCONSISTENT);
438
439     if (cb -> version != CHAIN_BLK_1)
440          return (NEW_VERSION);
441
442     return (0);
443}
444
445int write_chain (cb)
446chain_blk *cb;
447{
448     faddr cbaddr;
449
450     cbaddr = chain_addr (cb -> current);
451     if (cbaddr == 0)
452          return (NO_SUCH_TRN);
453
454     if (nuclear) {
455          if (awrite (a_control_f, (char *) cb, sizeof (chain_blk), cbaddr) != sizeof (chain_blk))
456               return (NO_WRITE);
457     }
458     else {
459          lseek (u_control_f, (long)cbaddr, 0);
460          if (write (u_control_f, (char *) cb, sizeof (chain_blk)) != sizeof (chain_blk))
461               return (NO_WRITE);
462     }
463
464     return (0);
465}
466
467/*
468 *
469 * read_trn -- routine to read a transaction from the transaction file.
470 *
471 */
472int read_trn (trn_addr, th, th_subject, th_author, th_signature)
473faddr trn_addr;
474trn_hdr *th;
475char **th_subject, **th_author, **th_signature;
476{
477     char *author;
478
479     lseek (u_trn_f, (long)trn_addr, 0);
480     read (u_trn_f, (char *) th, sizeof (trn_hdr));
481
482     if (th -> unique != TRN_HDR_UNIQUE)
483          return (INCONSISTENT);
484
485     if (th -> version != TRN_HDR_1)
486          return(NEW_VERSION);
487
488     if (th_subject != NULL) {
489          *th_subject = malloc ((unsigned)(th -> subject_len));
490          lseek (u_trn_f, (long)(th -> subject_addr), 0);
491          read (u_trn_f, *th_subject, th -> subject_len);
492     }
493         
494     if (th_author != NULL || th_signature != NULL) {
495          author = malloc ((unsigned)(th -> author_len));
496          lseek (u_trn_f, (long)(th -> author_addr), 0);
497          read (u_trn_f, author, th -> author_len);
498     }
499
500     if (th_author != NULL)
501          *th_author = author;
502
503     if (th_signature != NULL) {
504          if (strlen(author)+1 == th -> author_len) {
505               *th_signature = new_string(author);      /* No signature, return author */
506          } else {
507               *th_signature = new_string(&author[strlen(author)+1]);
508          }
509          if (th_author == NULL)
510               free(author);
511     }
512               
513     return(0);
514}
515         
516
517/*
518 *
519 * core_abort () -- Routine for use by core routines to clean things up.
520 *
521 */
522core_abort ()
523{
524     int dummy;
525
526     if (nuclear) {
527          aabort(a_control_f);
528          nuclear = FALSE;
529     }
530
531     if (abort_file != NULL) {
532          tclose (abort_file,&dummy);
533          abort_file = NULL;
534     }
535
536     if (read_lock)
537          finish_read();
538
539     forget_super();
540
541     return;
542}
543
544/*
545 *
546 * fsize () -- Routine to find out the size of a file.
547 *
548 */
549fsize (d)
550int d;
551{
552     struct stat buf;
553
554     if (fstat (d, &buf) < 0)
555          return (0);
556
557     return (buf.st_size);
558}
559/*
560 *
561 * fis_owner () -- Routine to find out if uid is owner of file.
562 *
563 */
564fis_owner (d, uid)
565int d,uid;
566{
567     struct stat buf;
568
569     if (fstat (d, &buf) < 0)
570          return (0);
571
572     return (uid == buf.st_uid);
573}
574
575/*
576 *
577 * has_trn_access -- Routine to return true if current user can access
578 *                   transaction.
579 *
580 */
581bool has_trn_access(author,mode)
582char *author;
583char mode;
584{
585     char *test_modes;
586
587     if (has_privs)
588          return(TRUE);                         /* linked in */
589
590     switch (mode) {
591     case 'd':
592          if (!strcmp(author,rpc_caller)) {
593               test_modes = "o";
594          } else {
595               test_modes = "d";
596          }
597          return (acl_check(mtg_acl,rpc_caller,test_modes));
598
599     case 'r':
600          return (acl_check(mtg_acl,rpc_caller,"r") ||
601                  ((!strcmp (author, rpc_caller)) && acl_check(mtg_acl,rpc_caller,"o")));
602     default:
603          panic ("Invalid mode");
604          /*NOTREACHED*/
605     }
606}         
607/*
608 *
609 * has_mtg_access -- Routine to return true if current user can access
610 *                   mtg, with given mode.
611 *
612 */
613bool has_mtg_access(mode)
614char mode;
615{
616     char *test_modes;
617     char mode_str[3];
618
619     if (has_privs)                             /* linked in stuff */
620          return (TRUE);               
621
622     switch (mode) {
623     case 'w':
624     case 'a':
625     case 'r':
626     case 's':
627     case 'o':
628          mode_str[0] = mode;
629          mode_str[1] = '\0';
630          test_modes = mode_str;
631          break;
632
633     case 'c':
634          test_modes = "c";
635          break;
636
637     default:
638          panic("Invalid mode");
639     }
640
641     return(acl_check(mtg_acl,rpc_caller,test_modes));
642}         
643/*
644 *
645 * panic -- just a printf
646 *
647 */
648panic(str)
649char *str;
650{
651     printf("panic: %s\n",str);
652     perror("discuss");
653     exit(1);
654}
655
656#ifdef ZEPHYR
657/*
658 *
659 * mtg_znotify -- send off a Zephyr notification as appropriate
660 *
661 */
662
663static const char * this_host = (const char *) NULL;
664
665void mtg_znotify(mtg_name, subject, author, signature)
666        char *mtg_name, *subject, *author, *signature;
667{
668        register dsc_acl_entry *ae;
669        register int n;
670        ZNotice_t notice;
671        char *msglst[5],bfr[30],fullpath[256];
672        int code, list_size;
673
674        if (!use_zephyr)
675            return;
676
677        if (!this_host) {
678            /* perform initializations */
679            char *h;
680            char host[100];
681            struct hostent *hent;
682            if (gethostname(host,100) != 0)
683                return;
684            hent = (struct hostent *) gethostbyname(host);
685            if (hent == 0)
686                return;
687            h = (char *) malloc (strlen (hent->h_name) + 1);
688            if (!h)
689                return;
690            strcpy (h, hent->h_name);
691            this_host = h;
692            ZInitialize();
693        }
694
695        /* Set up the notice structure */
696        bzero(&notice, sizeof(notice));
697
698        sprintf(fullpath,"%s:%s", this_host, mtg_name);
699        ZOpenPort(NULL);
700        notice.z_kind = UNSAFE;
701        notice.z_port = 0;
702        notice.z_class = "DISCUSS";
703        notice.z_class_inst = fullpath;
704        notice.z_opcode = "NEW_TRN";
705        notice.z_sender = 0;
706        if (signature == NULL)
707             notice.z_default_format = "New transaction [$1] entered in $2\nFrom: $3\nSubject: $4";
708        else
709             notice.z_default_format = "New transaction [$1] entered in $2\nFrom: $3 ($5)\nSubject: $4";
710        msglst[0] = bfr;
711        sprintf(msglst[0],"%04d",super.highest);
712        msglst[1] = super_long_name;
713        msglst[2] = author;
714        msglst[3] = subject;
715        list_size = 4;
716        if (signature != NULL) {
717             msglst[4] = signature;
718             list_size = 5;
719        }
720
721        /* Does "*" have read access? If so, just send out a global
722         * notice.
723         */
724
725        /* XXX
726         * Check at some point for people who don't have access, etc.
727         */
728
729        for (ae = mtg_acl->acl_entries, n=mtg_acl->acl_length;
730             n;
731             ae++, n--) {
732                if ((strcmp("*", ae->principal) == 0) &&
733                    acl_is_subset("r", ae->modes))
734                        break;
735        }
736        if (n) {
737                notice.z_recipient = "";
738                /* We really don't care if it gets through... */
739                code = ZSendList(&notice,msglst,list_size,ZNOAUTH);
740                return;
741        }
742        for (ae = mtg_acl->acl_entries, n=mtg_acl->acl_length;
743             n;
744             ae++, n--) {
745                if (acl_is_subset("r", ae->modes)) {
746                        notice.z_recipient = ae->principal;
747                        ZSendList(&notice,msglst,list_size,ZNOAUTH);
748                }
749        }
750}
751#endif /* ZEPHYR */
Note: See TracBrowser for help on using the repository browser.