1<?xml version="1.0" encoding="UTF-8"?> 2<!DOCTYPE egbokdoc SYSTEM "dtd/egbokdoc.dtd"> 3<!-- $Id: 2.0arch.xml,v 1.2 2002/05/24 04:05:43 hbo Exp $ 4 Description of sudoscript's 2.0 architecture 5--> 6 7<egbokdoc> 8 9<title> 10Sudoscript 2.0 Architecture 11</title> 12 13<maintainer> 14 <name>Howard Owen</name> 15 <affiliation>EGBOK Consultants</affiliation> 16 <email>hbo@egbok.com</email> 17</maintainer> 18<content> 19 20<section title="Introduction"> 21<para> 22 The original sudoscript architecture was a simple response to the 23 problem of allowing software engineers to run root shells on their 24 workstations. Generally, these users would be the only ones running 25 sudoshell on their machine. This was fortunate, because the original 26 architecture made no allowance for multiple simultaneous 27 users. There was a single logging FIFO and a single log 28 file. Multiple users could invoke sudoshell, but all their output 29 would be thrown together in the log file, without any separation of 30 the various sessions. As a practical matter, user input could 31 usually be differentiated by looking at the prompt. But since PS1 32 is settable by the user, and therefore varies quite a bit, it 33 couldn't be counted on to allow such differentiation. 34</para> 35</section> 36<section title="Tommy Smith's Idea"> 37<para> 38 Some mechanism was required to allow session differentiation. I got 39 an email from Tommy Smith suggesting that separate log files could be 40 used to allow identification of sessions. This struck me as a very 41 good idea. I started to think about how that could be 42 implemented. Forking a logging daemon per session seemed like it 43 would be fairly easy. I had a prototype doing that pretty quickly. 44 About the same time, I was exploring an idea from Adam Morris that 45 would get rid of sudoscriptd altogether, and replace in with a 46 forked FIFO server in sudoshell. I took a look at his C code that 47 implemented this idea, and tried to replicate it in Perl. I ran into 48 difficulty with keeping the terminal session attached to 49 script(1). Regardless of whether I implemented the daemon in the 50 parent or the child, I couldn't keep stdin/stdout attached to the 51 'system script' call. That, and 22 Dell 1650 servers landing on my 52 desk stopped my experiments for a time. 53</para> 54</section> 55<section title="The Second Idea"> 56<para> 57 When I revisited the code, I decided that I didn't want to get rid 58 of the daemon, because it allowed me to manage the size of the logs 59 produced. Using script(1) meant that large quantities of data, far 60 in excess of that produced by sudo, could be produced by 61 sudoscript. Though I couldn't predict how much data a particular 62 user might produce, I was concerned about overflowing logging 63 partitions. In the 1.0 architecture, the singular daemon kept an 64 eye on the log file. With multiple daemons, I realized, this job 65 would be a lot more complicated. I thought through a couple of 66 schemes that had the front-end daemon orchestrating log file 67 rotation among the back-end loggers. The main difficulty was that 68 the daemon in a position to know about all outstanding sessions 69 didn't "own" the log files. This made it harder to ensure 70 a timely rotation so that data wasn't dropped, while making it easier 71 to miss logs that needed compressing because a back-end daemon had 72 shut down abnormally. I decided that the whole deal was a threat to 73 overall reliability of sudoscript. 74</para> 75<para> 76 I then got the idea of merging all the session data back into 77 another daemon. This daemon would manage a merger FIFO, and coalesce 78 all session data, pre-tagged with a session ID, back into a single 79 log file. The daemon could then manage the log in the same way as 80 the 1.0 daemon did. The overall architecture was significantly more 81 complicated, but it looked to me like it could be reliable if 82 properly implemented. And there were no frills, either. All the 83 complexity had a specific purpose that no simpler architecture I 84 could think of would achieve. 85</para> 86<para> 87 88 I also decided that I would use syslog to track session startup and 89 shutdown. A short digression regarding syslog is in order 90 here. Since I couldn't control the possibly large quantity of data 91 sudoscript would log, I was reluctant to use syslog for the 92 script(1) data itself. When managing my own log, I was able to 93 trade off between longevity and space in a way that made sense to 94 me. But if I was using syslog, I could end up imposing that trade off 95 on a system log file, where it might be less appropriate. For 96 example, sudoscript 2.0 uses the AUTHPRIV syslog facility. On Red 97 Hat Linux, the default syslog.conf puts messages with this facility 98 into /var/log/secure. If sudoscript were to log all of the script(1) 99 data through to /var/log/secure, then that file would have to turn 100 over frequently. This could flush other important security data out 101 of the system more quickly than appropriate. Also, the sheer 102 quantity of data, combined with the ugliness of script(1) output, 103 would make these logs harder to read. I could use a different 104 facility for the data, but another feature of syslog makes me 105 hesitate to use it. At many sites, particularly those that are Sun 106 based, remote loghosts are employed. I think it's a really bad idea 107 to log by-definition sensitive data over the network in the 108 clear. The large quantity is a factor here as well. Given these 109 considerations, I have decided to stick with a private log file. 110</para> 111</section> 112<section title="The 2.0 Architecture"> 113<para> 114 I have a <link href="2.0arch.gif" text="rather large GIF image" /> of 115 the 2.0 architecture. If you open this image in a separate window, it 116 might help you understand the explanations that follow. 117</para> 118<para> 119 When sudoscriptd starts, it opens a FIFO called 120 "/var/run/sudoscriptd/rendevous". It then forks a 121 child. The parent process is the sudoscript "master 122 daemon." The child process is the "merger daemon". 123 It opens a FIFO called "/var/run/sudoscriptd/merge". It 124 also opens the log file, "/var/log/sudoscript", for 125 append. The merger goes into a read loop on the merge FIFO. As data 126 appears on this FIFO, the merger checks the size of the log file and 127 forks a rotator/compressor if the size exceeds 2 MB. Meanwhile, the 128 master daemon has gone into a read loop on its FIFO. 129</para> 130<para> 131 When sudoshell starts, it contacts the master daemon over the 132 rendezvous FIFO. It sends a string like "HELO hbo 133 12345". The latter two fields are the username that invoked 134 sudoshell (taken from the sudo environment, if sudoshell was run, or 135 ran itself with sudo, or just 'root' if it was invoked with 136 privilege) and sudoshell's own process ID. Sudoshell then installs 137 a SIGHUP handler and calls Posix::pause to go to sleep. The master 138 daemon spawns a logger for the sudoshell session. This child opens 139 the merge FIFO for write, and creates a session FIFO using the 140 username and PID derived from the HELO string. It then signals the 141 PID given with a SIGHUP, and goes goes into a loop reading the 142 session FIFO, tagging the data received with the username and PID 143 and writing it to the merge FIFO. Sudoshell wakes up when it 144 receives the SIGHUP, and invokes script(1) on the session FIFO, 145 whose name it derives from its own username and PID. 146</para> 147<para> 148 When the user exits from script(1), sudoshell sends another string 149 to the frontend daemon, identical to the first, except that 150 "HELO" is replaced with "GDBY". Sudoshell then 151 exits. When the master daemon receives the GDBY message, it looks up 152 the session in a table it maintains. It uses the child PID stored 153 there to signal the session daemon with a SIGHUP. It then removes 154 that session from its table. The session daemon cleans up and exits 155 when it receives this signal. 156</para> 157<para> 158 When the master daemon receives a SIGHUP, it loops through its 159 session table and signals each associated logger with a SIGHUP. 160 It then does the same for the merger daemon. 161</para> 162</section> 163<section title="Conclusion"> 164<para> 165 So, that's the complete life-cycle of the 2.0 166 sudoscript system. As noted above, important events are logged 167 to syslog with facility AUTHPRIV. This provides a concise record 168 of session activity, which can be used to search the larger log file 169 for particular sessions. 170</para> 171</section> 172</content> 173</egbokdoc> 174 175