source: trunk/athena/bin/discuss/server/core.c @ 15700

Revision 15700, 37.2 KB checked in by ghudson, 24 years ago (diff)
From kolya: fix buffer overflows.
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 *
10 *      $Id: core.c,v 1.40 2001-02-28 20:44:23 ghudson Exp $
11 *
12 *
13 * core.c --    Routines that are the meat of discuss.  These provide user
14 *              callable routines.
15 *
16 */
17#ifndef lint
18static char rcsid_core_c[] =
19    "$Id: core.c,v 1.40 2001-02-28 20:44:23 ghudson Exp $";
20#endif /* lint */
21
22
23/* Derived from CORE.PAS 06/21/86 by SRZ */
24
25#include <discuss/types.h>
26#include <discuss/dsc_et.h>
27#include <discuss/interface.h>
28#include "mtg.h"
29#include <discuss/tfile.h>
30#include "atom.h"
31#include <discuss/acl.h>
32#include "internal.h"
33#include <errno.h>
34#include <sys/types.h>
35#include <sys/file.h>
36#include <sys/stat.h>
37#include <sys/param.h>
38#include <stdio.h>
39#include <string.h>
40#if HAVE_FCNTL_H
41#include <fcntl.h>
42#endif
43
44#ifndef min
45#define min(a, b) (a < b ? a : b)
46#endif
47extern char *malloc();
48extern char *new_string();
49extern long time();
50extern off_t lseek();
51
52extern mtg_super super;
53extern char *super_chairman;
54extern char *super_long_name;
55extern char current_mtg [];
56extern int u_trn_f,u_control_f,u_acl_f;
57extern bool nuclear;
58extern bool mtg_swapped;
59extern afile a_control_f;
60extern char rpc_caller [];
61extern int errno;
62extern int has_privs;
63extern int no_nuke;
64extern tfile abort_file;
65extern dsc_acl *mtg_acl;
66
67
68/*
69 *
70 * add_trn () --
71 * adds a transaction to the given meeting, either as a reply or an
72 * original transaction.  Returns an error code, and the transaction number
73 * given to the transaction
74 *
75 */
76add_trn (mtg_name, source_file, subject, reply_trn, result_trn, result)
77char *mtg_name;
78tfile source_file;
79char *subject;
80trn_nums reply_trn;             /* trn replying to;  0 if original */
81trn_nums *result_trn;           /* trn number given to added trn */
82int *result;
83{
84     add_trn_priv (mtg_name, source_file, subject, NULL, reply_trn, 0,
85                   rpc_caller, (date_times) time ((long *)0), 0,
86                   result_trn, result);
87}
88
89/*
90 *
91 * add_trn2 () --
92 * adds a transaction to the given meeting, either as a reply or an
93 * original transaction.  Returns an error code, and the transaction number
94 * given to the transaction.  Also allows a signature for the author.
95 *
96 */
97add_trn2 (mtg_name, source_file, subject, signature, reply_trn, result_trn, result)
98char *mtg_name;
99tfile source_file;
100char *subject, *signature;
101trn_nums reply_trn;             /* trn replying to;  0 if original */
102trn_nums *result_trn;           /* trn number given to added trn */
103int *result;
104{
105     add_trn_priv (mtg_name, source_file, subject, signature, reply_trn, 0,
106                   rpc_caller, (date_times) time ((long *)0), 0,
107                   result_trn, result);
108}
109
110
111/* add_trn_priv:  For those who know exactly what they want and who they are */
112
113add_trn_priv (mtg_name, source_file, subject, signature, reply_trn, desired_trn, author, date_entered, flags, result_trn, result)
114char *mtg_name;
115tfile source_file;
116char *subject;
117char *signature;
118trn_nums reply_trn;             /* trn replying to;  0 if original */
119trn_nums desired_trn;           /* trn num desired */
120char *author;
121date_times date_entered;
122int flags;
123trn_nums *result_trn;           /* trn number given to added trn */
124int *result;
125{
126     chain_blk reply_cb, cb, spare_cb;
127     int tfs,tocopy,i,len;
128     char buffer[512],*bptr,*cp;
129     trn_hdr th;
130
131/*   printf ("add_trn:  mtg %s, subject %s, reply %d\n",
132             mtg_name, subject, reply_trn); */
133     topen (source_file, "r", result);
134     if (*result) return;
135
136     abort_file = source_file;                  /* for abort's sake */
137
138     *result = open_mtg (mtg_name);
139     if (*result) { core_abort (); return; }
140
141     if (reply_trn) {
142          if (!has_mtg_access('a')) {
143               *result = NO_ACCESS;
144               core_abort (); return;
145          }
146     } else {
147          if (!has_mtg_access('w')) {
148               *result = NO_ACCESS;
149               core_abort (); return;
150          }
151     }
152
153     if (!no_nuke) {
154          a_control_f = aopen (u_control_f);
155          nuclear = TRUE;
156     }
157
158     *result = read_super ();
159     if (*result) { core_abort(); return; }
160
161     if (super.date_created == 0) {     /* Meeting has been expunged */
162          write_super();
163
164          if (!no_nuke) {
165               aclose(a_control_f);
166               nuclear = 0;
167          }
168
169          *result = open_mtg (mtg_name);
170          if (*result) { core_abort (); return; }
171
172          if (!no_nuke) {
173               a_control_f = aopen (u_control_f);
174               nuclear = TRUE;
175          }
176
177          *result = read_super ();
178          if (*result) { core_abort(); return; }
179     }   
180
181     /* check reply_trn */
182     if (reply_trn != 0) {
183          *result = read_chain (reply_trn, &reply_cb);
184          if (*result) { core_abort(); return; }
185          if (reply_cb.flags & CB_DELETED) {
186               *result = DELETED_TRN;
187               core_abort (); return;
188          }
189     }
190
191     if (desired_trn == 0 || desired_trn <= super.highest)
192          super.highest++;
193     else
194          super.highest = desired_trn;
195     
196     /* Initialize chain block */
197     cb.version = CHAIN_BLK_1;
198     cb.unique = CHAIN_BLK_UNIQUE;
199     cb.current = super.highest;
200     cb.prev = super.last;
201     cb.next = 0;
202     cb.nref = 0;
203     cb.chain_fref = 0;
204     cb.chain_lref = 0;
205     cb.flags = flags & ~CB_DELETED;
206     cb.filler = 0;
207     cb.trn_addr = fsize (u_trn_f);
208
209     if (reply_trn != 0) {                              /* info from pref */
210          cb.trn_chain = reply_cb.trn_chain;
211          read_chain (cb.trn_chain, &spare_cb);
212          cb.pref = spare_cb.chain_lref;
213     } else {
214          cb.pref = 0;                                  /* this is fref */
215          cb.trn_chain = ++super.highest_chain;
216     }
217
218     if (write_chain (&cb) != 0)                        /* write it out */
219          goto werror;
220
221     /* update fref & lref of chain */
222     read_chain (cb.trn_chain, &spare_cb);
223     spare_cb.chain_lref = cb.current;                  /* update lref */
224     if (cb.pref == 0)
225          spare_cb.chain_fref = cb.current;
226
227     if (write_chain (&spare_cb) != 0)
228          goto werror;
229
230     /* update nref of pref */
231     if (reply_trn != 0) {
232          read_chain (cb.pref, &spare_cb);
233          spare_cb.nref = cb.current;
234          write_chain (&spare_cb);
235     }
236
237     /* update next of prev */
238     if (cb.prev != 0) {
239          read_chain (cb.prev, &spare_cb);
240          spare_cb.next = cb.current;
241          write_chain (&spare_cb);
242     }
243
244     /* and finish up the super block info */
245     super.last = cb.current;
246     if (super.first == 0)
247          super.first = cb.current;
248     super.date_modified = date_entered;
249     super.high_water += sizeof (chain_blk);
250
251     if (signature != NULL && (*signature == '\0' || !strcmp(author, signature)))
252          signature = NULL;                     /* Signature is empty */
253
254     /* now write out the transaction to the trn file */
255     /* First, eliminate NL in subject */
256     cp = strchr(subject, '\n');
257     if (cp != NULL)
258          *cp = '\0';
259
260     th.version = TRN_HDR_1;
261     th.unique = TRN_HDR_UNIQUE;
262     th.current = cb.current;
263     th.orig_pref = cb.pref;
264     th.date_entered = super.date_modified;
265     th.num_lines = 0;                  /* count these later */
266     th.num_chars = tfsize (source_file);
267     th.prev_trn = super.highest_trn_addr;
268     super.highest_trn_addr = cb.trn_addr;
269     th.subject_len = strlen (subject) + 1;
270     th.author_len = strlen (author) + 1;
271     if (signature != NULL)
272          th.author_len += strlen (signature) + 1;
273     th.subject_addr = cb.trn_addr + sizeof(trn_hdr);
274     th.author_addr = th.subject_addr + th.subject_len;
275     th.text_addr = th.author_addr + th.author_len;
276
277     if (mtg_swapped)
278          swap_trn(&th);
279
280     lseek (u_trn_f, (long)0, 2);
281     if (write (u_trn_f, (char *) &th, sizeof (th)) != sizeof (th)) goto werror;
282
283     if (mtg_swapped)                                   /* Swap it back */
284          swap_trn(&th);
285
286     if (write (u_trn_f, subject, th.subject_len) != th.subject_len) goto werror;
287     if (signature == NULL) {
288          if (write (u_trn_f, author, th.author_len) != th.author_len) goto werror;
289     } else {
290          len = strlen(author)+1;
291          if (write (u_trn_f, author, len) != len) goto werror;
292          len = th.author_len - len;
293          if (write (u_trn_f, signature, len) != len) goto werror;
294     }
295
296     /* copy transaction from source_file, counting NL's. */
297     tfs = th.num_chars;
298     while (tfs > 0) {
299          tocopy = min (512, tfs);
300          tocopy = tread (source_file, buffer, tocopy, result);
301          if (*result) { core_abort (); return; }
302          for (bptr = buffer, i = 0; i < tocopy; bptr++,i++)
303               if (*bptr == '\n')
304                    th.num_lines++;
305          if (write (u_trn_f, buffer, tocopy) != tocopy) goto werror;
306          tfs -= tocopy;
307     }
308
309     tclose(source_file,result);
310     abort_file = NULL;
311
312     if (mtg_swapped)
313          swap_trn(&th);
314
315     lseek(u_trn_f, (long)(cb.trn_addr), 0);
316     if (write (u_trn_f, (char *) &th, sizeof (trn_hdr)) != sizeof (trn_hdr)) goto werror;      /* update num_lines */
317
318     super.trn_fsize = fsize (u_trn_f);
319
320#if HAVE_ZEPHYR
321
322     /* Send this out...we want to do this BEFORE calling write_super
323      * because things get freed...
324      */
325     if (!(super.flags & MTG_NOZEPHYR))
326          mtg_znotify(mtg_name, subject, author, signature);
327#endif
328     
329     /* all done, start winding down */
330     write_super();
331
332     if (!no_nuke) {
333          fsync(u_trn_f);
334          aclose(a_control_f);
335          nuclear = 0;
336     }
337
338     *result = 0;
339     *result_trn = cb.current;
340     return;
341
342werror:
343     core_abort();
344     *result = NO_WRITE;
345     return;
346}
347/*
348 *
349 * expunge_trn () -- Entry to mark a given transaction as expunged.
350 *                   This makes a kosher chain_blk, except there's
351 *                   no transaction info associated with this.
352 *
353 */
354expunge_trn(mtg_name, desired_trn, result)
355char *mtg_name;
356trn_nums desired_trn;
357int *result;
358{
359     chain_blk cb;
360
361     *result = open_mtg (mtg_name);
362     if (*result) { core_abort (); return; }
363
364     if (!has_mtg_access('c')) {
365          *result = NO_ACCESS;
366          core_abort (); return;
367     }
368
369     if (!no_nuke) {
370          a_control_f = aopen (u_control_f);
371          nuclear = TRUE;
372     }
373
374     *result = read_super ();
375     if (*result) { core_abort(); return; }
376
377     if (desired_trn == 0 || desired_trn <= super.highest)
378          super.highest++;
379     else
380          super.highest = desired_trn;
381     
382     /* Initialize chain block */
383     cb.version = CHAIN_BLK_1;
384     cb.unique = CHAIN_BLK_UNIQUE;
385     cb.current = super.highest;
386     cb.prev = 0;
387     cb.next = 0;
388     cb.nref = 0;
389     cb.chain_fref = 0;
390     cb.chain_lref = 0;
391     cb.flags |= CB_DELETED;
392     cb.filler = 0;
393     cb.trn_addr = 0;
394
395     if (write_chain (&cb) != 0)                        /* write it out */
396          goto werror;
397
398     super.date_modified = time(0);
399     super.high_water += sizeof (chain_blk);
400
401     write_super();
402
403     if (!no_nuke) {
404          aclose(a_control_f);
405          nuclear = 0;
406     }
407
408     *result = 0;
409     return;
410
411werror:
412     core_abort();
413     *result = NO_WRITE;
414     return;
415}
416
417/*
418 *
419 * get_trn_info () --
420 * returns information about the given transaction in info, with an error
421 * code as its return argument
422 *
423 */
424get_trn_info (mtg_name, trn, info, result)
425char *mtg_name;
426trn_nums trn;
427trn_info *info;
428int *result;
429{
430     chain_blk cb,spare_cb;
431     trn_hdr th;
432     char *th_subject,*th_author;
433
434/*   printf ("get_trn_info: mtg %s, trn %d\n",
435             mtg_name, trn);*/
436
437     /* safety -- set info up right */
438     info -> version = 0;
439     info -> current = 0;
440     info -> prev = 0;
441     info -> next = 0;
442     info -> pref = 0;
443     info -> nref = 0;
444     info -> fref = 0;
445     info -> lref = 0;
446     info -> chain_index = 0;
447     info -> date_entered = 0;
448     info -> num_lines = 0;
449     info -> num_chars = 0;
450     info -> subject = new_string ("");
451     info -> author = new_string ("");
452
453
454     *result = open_mtg (mtg_name);
455     if (*result) return;
456
457     start_read();                              /* starting to read */
458
459     *result = read_super ();
460     if (*result) { core_abort(); return; }
461
462     *result = read_chain (trn, &cb);
463     if (*result) { core_abort(); return; }
464
465     if (cb.trn_addr == 0) {
466          *result = DELETED_TRN;
467          core_abort();
468          return;
469     }
470
471     *result = read_chain (cb.trn_chain, &spare_cb);
472     if (*result) { core_abort(); return; }
473
474     *result = read_trn (cb.trn_addr, &th, &th_subject, &th_author, NULL);
475     if (*result) { core_abort(); return; }
476
477     finish_read();
478
479     if (!has_trn_access(th_author, 'r')) {
480          *result = NO_ACCESS;
481          goto null_info;
482     }
483
484     if ((cb.flags & CB_DELETED) && !has_trn_access(th_author, 'd')) {
485          *result = DELETED_TRN;
486          goto null_info;
487     }
488
489     info -> version = 1;
490     info -> current = cb.current;
491     info -> prev = cb.prev;
492     info -> next = cb.next;
493     info -> pref = cb.pref;
494     info -> nref = cb.nref;
495     info -> fref = spare_cb.chain_fref;
496     info -> lref = spare_cb.chain_lref;
497     info -> chain_index = cb.trn_chain;
498
499     info -> date_entered = th.date_entered;
500     info -> num_lines = th.num_lines;
501     info -> num_chars = th.num_chars;
502     free (info -> subject);
503     info -> subject = th_subject;
504     free (info -> author);
505     info -> author = th_author;
506
507     forget_super();
508
509     if (cb.flags & CB_DELETED)
510          *result = DELETED_TRN;
511     else
512          *result = 0;
513null_info:
514     return;
515}
516
517/*
518 *
519 * get_trn_info2 () --
520 * returns information about the given transaction in info, with an error
521 * code as its return argument.  This call returns expanded information,
522 * such as the flags.
523 *
524 */
525get_trn_info2 (mtg_name, trn, info, result)
526char *mtg_name;
527trn_nums trn;
528trn_info2 *info;
529int *result;
530{
531     chain_blk cb,spare_cb;
532     trn_hdr th;
533     char *th_subject,*th_author;
534
535/*   printf ("get_trn_info: mtg %s, trn %d\n",
536             mtg_name, trn);*/
537
538     /* safety -- set info up right */
539     info -> version = 0;
540     info -> current = 0;
541     info -> prev = 0;
542     info -> next = 0;
543     info -> pref = 0;
544     info -> nref = 0;
545     info -> fref = 0;
546     info -> lref = 0;
547     info -> chain_index = 0;
548     info -> date_entered = 0;
549     info -> num_lines = 0;
550     info -> num_chars = 0;
551     info -> subject = new_string ("");
552     info -> author = new_string ("");
553     info -> flags = 0;
554
555     *result = open_mtg (mtg_name);
556     if (*result) return;
557
558     start_read();                              /* starting to read */
559
560     *result = read_super ();
561     if (*result) { core_abort(); return; }
562
563     *result = read_chain (trn, &cb);
564     if (*result) { core_abort(); return; }
565
566     if (cb.trn_addr == 0) {
567          *result = DELETED_TRN;
568          core_abort();
569          return;
570     }
571
572     *result = read_chain (cb.trn_chain, &spare_cb);
573     if (*result) { core_abort(); return; }
574
575     *result = read_trn (cb.trn_addr, &th, &th_subject, &th_author, NULL);
576     if (*result) { core_abort(); return; }
577
578     finish_read();
579
580     if (!has_trn_access(th_author, 'r')) {
581          *result = NO_ACCESS;
582          goto null_info;
583     }
584
585     if ((cb.flags & CB_DELETED) && !has_trn_access(th_author, 'd')) {
586          *result = DELETED_TRN;
587          goto null_info;
588     }
589
590     info -> version = 1;
591     info -> current = cb.current;
592     info -> prev = cb.prev;
593     info -> next = cb.next;
594     info -> pref = cb.pref;
595     info -> nref = cb.nref;
596     info -> fref = spare_cb.chain_fref;
597     info -> lref = spare_cb.chain_lref;
598     info -> chain_index = cb.trn_chain;
599
600     info -> date_entered = th.date_entered;
601     info -> num_lines = th.num_lines;
602     info -> num_chars = th.num_chars;
603     free (info -> subject);
604     info -> subject = th_subject;
605     free (info -> author);
606     info -> author = th_author;
607     info -> flags = cb.flags;
608
609     forget_super();
610
611     if (cb.flags & CB_DELETED)
612          *result = DELETED_TRN;
613     else
614          *result = 0;
615null_info:
616     return;
617}
618
619/*
620 *
621 * get_trn_info3 () --
622 * returns information about the given transaction in info, with an error
623 * code as its return argument.  This call returns expanded information,
624 * such as the flags and signature.
625 *
626 */
627get_trn_info3 (mtg_name, trn, info, result)
628char *mtg_name;
629trn_nums trn;
630trn_info3 *info;
631int *result;
632{
633     chain_blk cb,spare_cb;
634     trn_hdr th;
635     char *th_subject,*th_author, *th_signature;
636
637/*   printf ("get_trn_info: mtg %s, trn %d\n",
638             mtg_name, trn);*/
639
640     /* safety -- set info up right */
641     info -> version = 0;
642     info -> current = 0;
643     info -> prev = 0;
644     info -> next = 0;
645     info -> pref = 0;
646     info -> nref = 0;
647     info -> fref = 0;
648     info -> lref = 0;
649     info -> chain_index = 0;
650     info -> date_entered = 0;
651     info -> num_lines = 0;
652     info -> num_chars = 0;
653     info -> subject = new_string ("");
654     info -> author = new_string ("");
655     info -> signature = new_string ("");
656     info -> flags = 0;
657
658     *result = open_mtg (mtg_name);
659     if (*result) return;
660
661     start_read();                              /* starting to read */
662
663     *result = read_super ();
664     if (*result) { core_abort(); return; }
665
666     *result = read_chain (trn, &cb);
667     if (*result) { core_abort(); return; }
668
669     if (cb.trn_addr == 0) {
670          *result = DELETED_TRN;
671          core_abort();
672          return;
673     }
674
675     *result = read_chain (cb.trn_chain, &spare_cb);
676     if (*result) { core_abort(); return; }
677
678     *result = read_trn (cb.trn_addr, &th, &th_subject, &th_author, &th_signature);
679     if (*result) { core_abort(); return; }
680
681     finish_read();
682
683     if (!has_trn_access(th_author, 'r')) {
684          *result = NO_ACCESS;
685          goto null_info;
686     }
687
688     if ((cb.flags & CB_DELETED) && !has_trn_access(th_author, 'd')) {
689          *result = DELETED_TRN;
690          goto null_info;
691     }
692
693     info -> version = 1;
694     info -> current = cb.current;
695     info -> prev = cb.prev;
696     info -> next = cb.next;
697     info -> pref = cb.pref;
698     info -> nref = cb.nref;
699     info -> fref = spare_cb.chain_fref;
700     info -> lref = spare_cb.chain_lref;
701     info -> chain_index = cb.trn_chain;
702
703     info -> date_entered = th.date_entered;
704     info -> num_lines = th.num_lines;
705     info -> num_chars = th.num_chars;
706     free (info -> subject);
707     info -> subject = th_subject;
708     free (info -> author);
709     info -> author = th_author;
710     free (info -> signature);
711     info -> signature = th_signature;
712     info -> flags = cb.flags;
713
714     forget_super();
715
716     if (cb.flags & CB_DELETED)
717          *result = DELETED_TRN;
718     else
719          *result = 0;
720null_info:
721     return;
722}
723
724
725/*
726 *
727 * set_trn_flags () -- Routine to set the flags (except DELETED) on a
728 *                     given transaction.
729 *
730 */
731set_trn_flags (mtg_name, trn, flags, result)
732char *mtg_name;
733trn_nums trn;
734short flags;
735int *result;
736{
737     chain_blk cb;
738     trn_hdr th;
739     char *th_author;
740
741     *result = open_mtg (mtg_name);
742     if (*result) return;
743
744     if (!no_nuke) {
745          a_control_f = aopen (u_control_f);
746          nuclear = TRUE;
747     }
748
749     *result = read_super ();
750     if (*result) { core_abort(); return; }
751
752     *result = read_chain (trn, &cb);
753     if (*result) { core_abort(); return; }
754
755     if ((cb.flags & CB_DELETED) || cb.trn_addr == 0) {
756          *result = DELETED_TRN;
757          core_abort (); return;
758     }
759
760     *result = read_trn (cb.trn_addr, &th, (char **)0, &th_author, NULL);
761     if (*result) { core_abort(); return; }
762
763     if (!has_trn_access(th_author,'d')) {
764          *result = NO_ACCESS;
765          free(th_author);
766          core_abort(); return;
767     }
768
769     free(th_author);
770
771     cb.flags = (cb.flags & CB_DELETED) | (flags & ~CB_DELETED);
772     write_chain (&cb);
773
774     forget_super();
775
776     if (!no_nuke) {
777          aclose (a_control_f);
778          nuclear = FALSE;
779     }
780
781     *result = 0;
782     return;
783}
784
785
786
787/*
788 *
789 * delete_trn () --
790 * deletes the given transaction from the current meeting.  Returns an
791 * error code
792 *
793 */
794delete_trn (mtg_name, trn, result)
795char *mtg_name;
796trn_nums trn;
797int *result;
798{
799     chain_blk cb, spare_cb;
800     char *th_author;
801     trn_hdr th;
802
803/*   printf ("delete_trn: mtg %s, trn %d\n",
804             mtg_name, trn);*/
805
806     *result = open_mtg (mtg_name);
807     if (*result) return;
808
809     if (!no_nuke) {
810          a_control_f = aopen (u_control_f);
811          nuclear = TRUE;
812     }
813
814     *result = read_super ();
815     if (*result) { core_abort(); return; }
816
817     *result = read_chain (trn, &cb);
818     if (*result) { core_abort(); return; }
819
820     if ((cb.flags & CB_DELETED) || cb.trn_addr == 0) {
821          *result = DELETED_TRN;
822          core_abort (); return;
823     }
824
825     *result = read_trn (cb.trn_addr, &th, (char **)0, &th_author, NULL);
826     if (*result) { core_abort(); return; }
827
828     if (!has_trn_access(th_author,'d')) {
829          *result = NO_ACCESS;
830          free(th_author);
831          core_abort(); return;
832     }
833
834     free(th_author);
835     
836     cb.flags |= CB_DELETED;
837     write_chain (&cb);
838
839     /* update next of prev */
840     if (cb.prev != 0) {
841          *result = read_chain (cb.prev, &spare_cb);
842          if (*result) { core_abort(); return; }
843
844          spare_cb.next = cb.next;
845          write_chain (&spare_cb);
846     }
847
848     /* update prev of next */
849     if (cb.next != 0) {
850          *result = read_chain (cb.next, &spare_cb);
851          if (*result) { core_abort(); return; }
852
853          spare_cb.prev = cb.prev;
854          write_chain (&spare_cb);
855     }
856
857     /* update nref of pref */
858     if (cb.pref != 0) {
859          *result = read_chain (cb.pref, &spare_cb);
860          if (*result) { core_abort(); return; }
861
862          spare_cb.nref = cb.nref;
863          write_chain (&spare_cb);
864     }
865
866     /* update pref of nref */
867     if (cb.nref != 0) {
868          *result = read_chain (cb.nref, &spare_cb);
869          if (*result) { core_abort(); return; }
870
871          spare_cb.pref = cb.pref;
872          write_chain (&spare_cb);
873     }
874
875     /* and update fref & lref of chain */
876     if (cb.nref == 0 || cb.pref == 0) {
877          *result = read_chain (cb.trn_chain, &spare_cb);
878          if (*result) { core_abort(); return; }
879
880          if (cb.nref == 0)
881               spare_cb.chain_lref = cb.pref;
882          if (cb.pref == 0)
883               spare_cb.chain_fref = cb.nref;
884          write_chain (&spare_cb);
885     }
886
887     /* and update, first and last of meeting */
888     if (cb.prev == 0)
889          super.first = cb.next;
890     if (cb.next == 0)
891          super.last = cb.prev;
892
893     write_super ();
894     if (!no_nuke) {
895          aclose (a_control_f);
896          nuclear = FALSE;
897     }
898
899     *result = 0;
900     return;
901}
902
903/*
904 *
905 * retrieve_trn () --
906 * retrieves a previously deleted transaction from the current meeting, if
907 * possible.  trn must refer to a deleted transaction.  An error code is
908 * returned
909 *
910 */
911retrieve_trn (mtg_name, trn, result)
912char *mtg_name;
913trn_nums trn;
914int *result;
915{
916     chain_blk cb, spare_cb, chain_cb;
917     trn_hdr th;
918     char *th_author;
919
920
921/*   printf ("retrieve_trn: mtg %s, trn %d\n",
922             mtg_name, trn);*/
923
924
925     *result = open_mtg (mtg_name);
926     if (*result) return;
927
928     if (!no_nuke) {
929          a_control_f = aopen (u_control_f);
930          nuclear = TRUE;
931     }
932
933     *result = read_super ();
934     if (*result) { core_abort(); return; }
935
936     *result = read_chain (trn, &cb);
937     if (*result) { core_abort(); return; }
938
939     if (!(cb.flags & CB_DELETED)) {
940          *result = TRN_NOT_DELETED;
941          core_abort (); return;
942     }
943
944     if (cb.trn_addr == 0) {
945          *result = EXPUNGED_TRN;
946          core_abort (); return;
947     }
948
949     /* for paranoia, read transaction */
950     *result = read_trn (cb.trn_addr, &th, (char **)0, &th_author, NULL);
951     if (*result) { core_abort(); return; }
952
953     if (!has_trn_access(th_author,'d')) {
954          *result = NO_ACCESS;
955          free(th_author);
956          core_abort(); return;
957     }
958
959     free(th_author);
960
961     /* now retrieving a transaction is hairier than deleting it, since
962        the previous and next, pref and nref could also have been deleted
963        since.  Also, intermediate ones could have been retrieved in the
964        interim.  So we go to our reference points (fref & lref), and
965        start from there.  There are three cases -- we are the new fref,
966        we are the new lref, or we are in the middle.  For prev & next,
967        we just start decrementing and incrementing until we get a
968        non-deleted transaction */
969     
970     *result = read_chain (cb.trn_chain, &chain_cb);
971     if (*result) { core_abort(); return; }
972
973     if (chain_cb.chain_fref > cb.current || chain_cb.chain_fref == 0) /* we are fref */
974          cb.pref = 0;
975     else
976          cb.pref = chain_cb.chain_fref;
977
978     if (chain_cb.chain_lref < cb.current)
979          cb.nref = 0;
980     else
981          cb.nref = chain_cb.chain_lref;
982
983     /* advance until we get past us */
984     while (cb.pref != 0) {
985          *result = read_chain (cb.pref, &spare_cb);
986          if (*result) { core_abort(); return; }
987
988          if (spare_cb.nref > cb.current || spare_cb.nref == 0)
989               break;
990          cb.pref = spare_cb.nref;
991     }
992
993     while (cb.nref != 0) {
994          *result = read_chain (cb.nref, &spare_cb);
995          if (*result) { core_abort(); return; }
996
997          if (spare_cb.pref < cb.current)
998               break;
999          cb.nref = spare_cb.pref;
1000     }
1001
1002     if (super.first > cb.current || super.first == 0) /* we are first */
1003          cb.prev = 0;
1004     else
1005          cb.prev = cb.current - 1;
1006
1007     if (super.last < cb.current)
1008          cb.next = 0;
1009     else
1010          cb.next = cb.current + 1;
1011
1012     while (cb.prev != 0) {
1013          *result = read_chain (cb.prev, &spare_cb);
1014          if (*result) { core_abort(); return; }
1015
1016          if (!(spare_cb.flags & CB_DELETED))
1017               break;
1018          cb.prev--;
1019     }
1020     while (cb.next != 0) {
1021          *result = read_chain (cb.next, &spare_cb);
1022          if (*result) { core_abort(); return; }
1023
1024          if (!(spare_cb.flags & CB_DELETED))
1025               break;
1026          cb.next++;
1027     }
1028
1029     /* invariant -- current_block is all set (except for deleted) */
1030     cb.flags &= ~(CB_DELETED);
1031     write_chain (&cb);
1032
1033     /* update next of prev */
1034     if (cb.prev != 0) {
1035          *result = read_chain (cb.prev, &spare_cb);
1036          if (*result) { core_abort(); return; }
1037
1038          spare_cb.next = cb.current;
1039          write_chain (&spare_cb);
1040     }
1041
1042     /* update prev of next */
1043     if (cb.next != 0) {
1044          *result = read_chain (cb.next, &spare_cb);
1045          if (*result) { core_abort(); return; }
1046
1047          spare_cb.prev = cb.current;
1048          write_chain (&spare_cb);
1049     }
1050
1051     /* update nref of pref */
1052     if (cb.pref != 0) {
1053          *result = read_chain (cb.pref, &spare_cb);
1054          if (*result) { core_abort(); return; }
1055
1056          spare_cb.nref = cb.current;
1057          write_chain (&spare_cb);
1058     }
1059
1060     /* update pref of nref */
1061     if (cb.nref != 0) {
1062          *result = read_chain (cb.nref, &spare_cb);
1063          if (*result) { core_abort(); return; }
1064
1065          spare_cb.pref = cb.current;
1066          write_chain (&spare_cb);
1067     }
1068
1069     /* and update fref & lref of chain */
1070     if (cb.nref == 0 || cb.pref == 0) {
1071          *result = read_chain (cb.trn_chain, &spare_cb);
1072          if (*result) { core_abort(); return; }
1073
1074          if (cb.nref == 0)
1075               spare_cb.chain_lref = cb.current;
1076          if (cb.pref == 0)
1077               spare_cb.chain_fref = cb.current;
1078          write_chain (&spare_cb);
1079     }
1080
1081     /* and update, first and last of meeting */
1082     if (cb.prev == 0)
1083          super.first = cb.current;
1084     if (cb.next == 0)
1085          super.last = cb.current;
1086
1087     write_super ();
1088     if (!no_nuke) {
1089          aclose (a_control_f);
1090          nuclear = FALSE;
1091     }
1092
1093     *result = 0;
1094     return;
1095}
1096
1097
1098
1099/*
1100 *
1101 * create_mtg () --
1102 * Creates a new meeting with the given long_mtg name, where location is the
1103 * it's place in the hierarchy, and the long_mtg_name is its canonical name.
1104 * The chairman of the new meeting is the current user.
1105 *
1106 */
1107create_mtg (location, long_mtg_name, public, result)
1108char *location,*long_mtg_name;
1109bool public;
1110int *result;
1111{
1112     create_mtg_priv (location, long_mtg_name, public, (date_times) time ((long *)0), rpc_caller, NULL, result);
1113}
1114
1115/* create_mtg_priv -- for people who know the chairman and date_created */
1116create_mtg_priv (location, long_mtg_name, public, date_created, chairman, new_acl, result)
1117char *location,*long_mtg_name,*chairman;
1118bool public;
1119date_times date_created;
1120dsc_acl *new_acl;
1121int *result;
1122{
1123     char str[256];
1124     trn_base tb;
1125     int loclen;
1126
1127/*   printf("create_mtg: long mtg %s, location %s, public %d\n",
1128            long_mtg_name, location, public);*/
1129
1130     loclen = strlen (location);
1131     if (location[0] != '/' || loclen == 0 || loclen >= MAXPATHLEN || location [loclen-1] == '/' || loclen+14 >= sizeof(str)) {
1132          *result = BAD_PATH;
1133          return;
1134     }
1135
1136     if (long_mtg_name [0] == '\0') {
1137          *result = BAD_MTG_NAME;
1138          return;
1139     }
1140
1141     /* First, create meeting directory */
1142     umask (077);                               /* Set access for sure */
1143     if (mkdir (location, 0700) < 0) {          /* rwx------ */
1144          if (errno == EEXIST)
1145               *result = DUP_MTG_NAME;
1146          else
1147               *result = BAD_PATH;
1148          return;
1149     }
1150
1151     /*
1152      * Then see if we should have access to build it..  Yes, this is
1153      * a crock, but UNIX doesn't have an easy way to
1154      * canonicalize a pathname
1155      */
1156
1157     *result = 0;
1158     
1159     if (!has_privs) {
1160          int aclfd;
1161          strcpy (str, location);
1162          strcat (str, "/../cacl");
1163
1164          if ((aclfd = open(str, O_RDONLY, 0700)) < 0) {
1165               *result = NO_ACCESS;
1166          } else {
1167               dsc_acl *tmp_acl = acl_read(aclfd);
1168               (void) close(aclfd);
1169
1170               if (tmp_acl == NULL ||
1171                   !acl_check(tmp_acl, rpc_caller, "a"))
1172                       *result = NO_ACCESS;
1173               (void) acl_destroy(tmp_acl);
1174          }
1175          if (*result) {
1176               (void) rmdir(location); /* we don't care if this fails; */
1177                                       /* we can't do anything about it */
1178               return;
1179          }
1180     }
1181     
1182     strcpy (str, location);
1183     strcat (str, "/control");
1184
1185     if ((u_control_f = open(str, O_RDWR | O_CREAT | O_EXCL, 0700)) < 0) {
1186          if (errno == EEXIST)
1187               *result = DUP_MTG_NAME;
1188          else if (errno == EACCES)
1189               *result = NO_ACCESS;
1190          else
1191               *result = BAD_PATH;
1192          return;
1193     }
1194     
1195     strcpy (str, location);
1196     strcat (str, "/transactions");
1197     
1198     if ((u_trn_f = open(str, O_RDWR | O_CREAT | O_EXCL, 0700)) < 0) {
1199          if (errno == EEXIST)
1200               *result = DUP_MTG_NAME;
1201          else if (errno == EACCES)
1202               *result = NO_ACCESS;
1203          else
1204               *result = BAD_PATH;
1205          close (u_control_f);
1206          return;
1207     }
1208
1209     mtg_swapped = FALSE;
1210
1211     /* Initialize super-block */
1212     super.version = MTG_SUPER_1;
1213     super.unique = MTG_SUPER_UNIQUE;
1214     super.first = 0;
1215     super.last = 0;
1216     super.lowest = 1;
1217     super.highest = 0;
1218     super.highest_chain = 0;
1219     super.date_created = super.date_modified = date_created;
1220     super.long_name_addr = 0;
1221     super.chairman_addr = 0;
1222     super.long_name_len = 0;
1223     super.chairman_len = 0;
1224
1225     super_long_name = new_string (long_mtg_name);
1226     super_chairman = new_string (chairman);
1227     super.flags = public ? MTG_PUBLIC : 0;
1228     super.chain_start = 1024;
1229     super.high_water = super.chain_start;
1230     super.trn_fsize = 0;
1231     super.highest_trn_addr = 0;
1232
1233     /* initialize trn_base */
1234     tb.version = TRN_BASE_1;
1235     tb.unique = TRN_BASE_UNIQUE;
1236     tb.date_created = super.date_created;
1237     tb.public_flag = public;
1238
1239     /* calculate address & lens of variable length fields */
1240     tb.long_name_addr = sizeof (tb);
1241     tb.long_name_len = strlen (super_long_name) + 1;
1242     tb.chairman_addr = tb.long_name_addr + tb.long_name_len;
1243     tb.chairman_len = strlen (super_chairman) + 1;
1244     write (u_trn_f, (char *) &tb, sizeof (tb));        /* trn base */
1245     write (u_trn_f, super_long_name, tb.long_name_len);
1246     write (u_trn_f, super_chairman, tb.chairman_len);
1247
1248     super.trn_fsize = sizeof (tb) + tb.long_name_len + tb.chairman_len;
1249
1250     write_super();
1251     
1252     strcpy (current_mtg, location);                    /* it's legal */
1253     if (mtg_acl != NULL)
1254          acl_destroy(mtg_acl);
1255     if (new_acl == NULL) {
1256          mtg_acl = acl_create ();
1257          acl_add_access(mtg_acl, chairman, "acdorsw"); /* add chairman */
1258          if (public == 1)
1259               acl_add_access(mtg_acl, "*", "a  orsw"); /* public mtg */
1260     } else
1261          mtg_acl = acl_copy(new_acl);
1262
1263
1264     strcpy (str, location);
1265     strcat (str, "/acl");
1266
1267     if ((u_acl_f = open (str, O_RDWR | O_CREAT | O_EXCL, 0700)) < 0) {
1268          *result = BAD_PATH;
1269          return;
1270     }
1271     acl_write (u_acl_f, mtg_acl);
1272     close (u_acl_f);
1273
1274     *result = 0;
1275     return;
1276}
1277
1278
1279/*
1280 *
1281 * get_mtg_info () --
1282 * returns information about the given meeting.  Return argument is an
1283 * error code
1284 *
1285 */
1286get_mtg_info (mtg_name, info, result)
1287char *mtg_name;
1288mtg_info *info;
1289int *result;
1290{
1291/*   printf ("get_mtg_info: mtg %s\n",
1292             mtg_name);*/
1293
1294     /* safety -- set strings up right */
1295     info -> chairman = new_string ("");
1296     info -> long_name = new_string ("");
1297     info -> location = new_string (mtg_name);
1298     info -> access_modes = new_string ("");
1299     info -> public_flag = TRUE;
1300
1301     *result = open_mtg (mtg_name);
1302     if (*result) {
1303          if (*result == MTG_MOVED) {
1304               char buf[100];
1305               int mf;
1306               char *cp;
1307
1308               snprintf(buf, sizeof(buf), "%s/forward", mtg_name);
1309               if ((mf = open(buf, O_RDONLY, 0700)) < 0) {
1310                    *result = INCONSISTENT;
1311                    return;
1312               }
1313               if (read(mf, buf, 100) < 0) {
1314                    *result = INCONSISTENT;
1315                    close(mf);
1316                    return;
1317               }
1318               close(mf);
1319               cp = strchr(buf, '\n');
1320               if (cp == NULL) {
1321                    *result = INCONSISTENT;
1322                    return;
1323               }
1324               *cp = '\0';
1325               cp = strchr(buf, ':');
1326               if (cp == NULL) {
1327                    *result = INCONSISTENT;
1328                    return;
1329               }
1330               *cp++ = '\0';
1331               free(info -> long_name);
1332               info -> long_name = new_string (buf);
1333               free(info -> location);
1334               info -> location = new_string (cp);
1335          }
1336          return;
1337     }
1338
1339     free(info -> access_modes);
1340     info -> access_modes = new_string (acl_get_access(mtg_acl, rpc_caller));
1341
1342     if (!has_mtg_access('s') && !has_mtg_access('r')) {
1343          *result = NO_ACCESS;
1344          return;
1345     }
1346
1347     start_read();                              /* starting to read */
1348
1349     *result = read_super ();
1350     if (*result) { core_abort(); return; }
1351
1352     finish_read();
1353
1354     info -> version = 2;
1355     free(info -> long_name);
1356     free(info -> chairman);
1357
1358     info -> long_name = new_string (super_long_name);
1359     info -> chairman = new_string (super_chairman);
1360     info -> first = super.first;
1361     info -> last = super.last;
1362     info -> lowest = super.lowest;
1363     info -> highest = super.highest;
1364     info -> date_created = super.date_created;
1365     info -> date_modified = super.date_modified;
1366     info -> public_flag = (super.flags & MTG_PUBLIC);
1367
1368     forget_super();
1369
1370     *result = 0;
1371     return;
1372}
1373
1374/*
1375 *
1376 * get_trn () --
1377 * gets the given transaction, and feeds it through dest_file.  Returns an
1378 * error code
1379 *
1380 */
1381get_trn (mtg_name, trn, dest_file, result)
1382char *mtg_name;
1383trn_nums trn;
1384tfile dest_file;
1385int *result;
1386{
1387     chain_blk cb;
1388     trn_hdr th;
1389     char buffer [512];
1390     int tocopy, tfs;
1391     char *th_author;
1392
1393/*   printf ("get_trn: mtg %s, trn %d\n",
1394             mtg_name, trn);*/
1395
1396     topen (dest_file, "w", result);
1397     abort_file = dest_file;
1398
1399     *result = open_mtg (mtg_name);
1400     if (*result) { core_abort (); return; }
1401
1402     start_read();                              /* starting to read */
1403
1404     *result = read_super ();
1405     if (*result) { core_abort(); return; }
1406
1407     *result = read_chain (trn, &cb);
1408     if (*result) { core_abort(); return; }
1409
1410     if (cb.trn_addr == 0) {
1411          *result = DELETED_TRN;
1412          core_abort();
1413          return;
1414     }
1415
1416     *result = read_trn (cb.trn_addr, &th, (char **)0, &th_author, NULL);
1417     if (*result) { core_abort(); return; }
1418
1419     finish_read();
1420
1421     if ((cb.flags & CB_DELETED) && !has_trn_access(th_author, 'd')) {
1422
1423          *result = DELETED_TRN;
1424          free(th_author);
1425          core_abort(); return;
1426     }
1427     if (!has_trn_access(th_author,'r')) {
1428          *result = NO_ACCESS;
1429          free(th_author);
1430          core_abort(); return;
1431     }
1432
1433     (void) free(th_author);
1434
1435     lseek (u_trn_f, (long)(th.text_addr), 0);
1436     tfs = th.num_chars;
1437     while (tfs > 0) {
1438          tocopy = min (512, tfs);
1439          read (u_trn_f, buffer, tocopy);
1440          twrite (dest_file, buffer, tocopy,result);
1441          tfs -= tocopy;
1442     }
1443
1444     tclose (dest_file,result);
1445     abort_file = NULL;
1446
1447     if (cb.flags & CB_DELETED)
1448          *result = DELETED_TRN;
1449     else
1450          *result = 0;
1451     return;
1452}
1453
1454/*
1455 *
1456 * remove_mtg () --
1457 * removes the given meeting  -- the physical contents of the meeting
1458 * are destroyed.
1459 *
1460 */
1461remove_mtg (mtg_name, result)
1462char *mtg_name;
1463int *result;
1464{
1465     char str[256];
1466
1467
1468/*   printf ("remove_mtg: mtg %s\n",
1469             mtg_name);*/
1470     
1471     *result = open_mtg (mtg_name);
1472     if (*result) return;
1473
1474     if (!has_mtg_access('c')) {
1475          *result = NO_ACCESS;
1476          return;
1477     }
1478         
1479     strcpy (str, mtg_name);
1480     strcat (str, "/control");
1481
1482     if (unlink (str) < 0) {
1483          if (errno != ENOENT) {
1484               *result = CANNOT_REMOVE;
1485               return;
1486          }
1487     }
1488
1489     strcpy (str, mtg_name);
1490     strcat (str, "/transactions");
1491
1492     unlink (str);
1493
1494     strcpy (str, mtg_name);
1495     strcat (str, "/acl");
1496
1497     unlink (str);
1498
1499     *result = 0;
1500     if (rmdir (mtg_name) < 0)
1501          *result = CANNOT_REMOVE;
1502
1503     *result = read_super();
1504     super.date_created = 0;
1505     write_super();
1506
1507     close (u_trn_f);                           /* bombs away */
1508     close (u_control_f);
1509     if (u_acl_f)
1510          close (u_acl_f);
1511     acl_destroy(mtg_acl);
1512     mtg_acl = NULL;
1513     current_mtg [0] = '\0';
1514
1515     return;
1516}
1517
1518/*
1519 *
1520 * updated_mtg () -- Quick procedure to check if the meeting is updated
1521 *                   with respect to a given time and transaction number.
1522 *                   An efficient procedure for a common operation -- doesn't
1523 *                   open the meeting unless it has to.
1524 *
1525 */
1526updated_mtg (mtg_name, date_attended, last, updated, result)
1527char *mtg_name;
1528int date_attended, last;
1529bool *updated;
1530int *result;
1531{
1532     char str[256];
1533     int mtg_name_len;
1534     mtg_super mysuper;
1535     struct stat sb;
1536     int uf;
1537
1538     *updated = 0;
1539     *result = 0;                               /* optimist */
1540
1541     mtg_name_len = strlen (mtg_name);
1542     if (mtg_name[0] != '/' || mtg_name_len == 0 || mtg_name_len >= MAXPATHLEN || mtg_name [mtg_name_len-1] == '/' || mtg_name_len + 9 >= sizeof(str)) {
1543          *result = BAD_PATH;
1544          return;
1545     }
1546
1547     strcpy (str, mtg_name);
1548     strcat (str, "/forward");
1549     if (!stat(str, &sb)) {             /* Show moved meetings as changed */
1550          *updated = TRUE;
1551          *result = 0;
1552          return;
1553     }
1554
1555     strcpy (str, mtg_name);
1556     strcat (str, "/control");
1557
1558     /* time makes no difference in our books */
1559     if ((uf = open(str, O_RDWR, 0700)) < 0) {
1560          if (errno == ENOENT)
1561               *result = NO_SUCH_MTG;
1562          else if (errno == EACCES)
1563               *result = NO_ACCESS;
1564          else
1565               *result = BAD_PATH;
1566          goto punt;
1567     }
1568
1569     /* forget locking (and stuff) for what we're doing */
1570     lseek (uf, (long)0, 0);
1571     read (uf, (char *) &mysuper, sizeof (mysuper));
1572     close(uf);
1573
1574     if (mysuper.unique == MTG_SUPER_UNIQUE_SWAP)
1575          swap_super(&mysuper);
1576
1577     *updated = (mysuper.last > last);
1578     if (mysuper.highest < last)
1579          *result = NO_SUCH_TRN;
1580
1581punt:
1582     return;
1583}
Note: See TracBrowser for help on using the repository browser.