author | Mahlon E. Smith <mahlon@martini.nu> |
Sat, 28 Feb 2009 06:52:48 +0000 | |
changeset 6 | 2d52adc4adcc |
parent 5 | 41a1542b3b10 |
permissions | -rw-r--r-- |
0 | 1 |
/* |
5
41a1542b3b10
Cleaned up bsdjail extension code a bit more and made the extconf check for
Michael Granger <ged@FaerieMUD.org>
parents:
2
diff
changeset
|
2 |
* bsdjail.c - JParallel extension for FreeBSD jail(2) functions |
0 | 3 |
* $Id$ |
4 |
* |
|
5 |
* Authors: |
|
6 |
* * Michael Granger <ged@FaerieMUD.org> |
|
5
41a1542b3b10
Cleaned up bsdjail extension code a bit more and made the extconf check for
Michael Granger <ged@FaerieMUD.org>
parents:
2
diff
changeset
|
7 |
* * Mahlon E. Smith <mahlon@martini.nu> |
0 | 8 |
* |
5
41a1542b3b10
Cleaned up bsdjail extension code a bit more and made the extconf check for
Michael Granger <ged@FaerieMUD.org>
parents:
2
diff
changeset
|
9 |
* Copyright (c) 2008, Michael Granger and Mahlon Smith |
41a1542b3b10
Cleaned up bsdjail extension code a bit more and made the extconf check for
Michael Granger <ged@FaerieMUD.org>
parents:
2
diff
changeset
|
10 |
* All rights reserved. |
41a1542b3b10
Cleaned up bsdjail extension code a bit more and made the extconf check for
Michael Granger <ged@FaerieMUD.org>
parents:
2
diff
changeset
|
11 |
* |
41a1542b3b10
Cleaned up bsdjail extension code a bit more and made the extconf check for
Michael Granger <ged@FaerieMUD.org>
parents:
2
diff
changeset
|
12 |
* Redistribution and use in source and binary forms, with or without |
41a1542b3b10
Cleaned up bsdjail extension code a bit more and made the extconf check for
Michael Granger <ged@FaerieMUD.org>
parents:
2
diff
changeset
|
13 |
* modification, are permitted provided that the following conditions are met: |
41a1542b3b10
Cleaned up bsdjail extension code a bit more and made the extconf check for
Michael Granger <ged@FaerieMUD.org>
parents:
2
diff
changeset
|
14 |
* |
41a1542b3b10
Cleaned up bsdjail extension code a bit more and made the extconf check for
Michael Granger <ged@FaerieMUD.org>
parents:
2
diff
changeset
|
15 |
* * Redistributions of source code must retain the above copyright notice, |
41a1542b3b10
Cleaned up bsdjail extension code a bit more and made the extconf check for
Michael Granger <ged@FaerieMUD.org>
parents:
2
diff
changeset
|
16 |
* this list of conditions and the following disclaimer. |
41a1542b3b10
Cleaned up bsdjail extension code a bit more and made the extconf check for
Michael Granger <ged@FaerieMUD.org>
parents:
2
diff
changeset
|
17 |
* |
41a1542b3b10
Cleaned up bsdjail extension code a bit more and made the extconf check for
Michael Granger <ged@FaerieMUD.org>
parents:
2
diff
changeset
|
18 |
* * Redistributions in binary form must reproduce the above copyright notice, |
41a1542b3b10
Cleaned up bsdjail extension code a bit more and made the extconf check for
Michael Granger <ged@FaerieMUD.org>
parents:
2
diff
changeset
|
19 |
* this list of conditions and the following disclaimer in the documentation |
41a1542b3b10
Cleaned up bsdjail extension code a bit more and made the extconf check for
Michael Granger <ged@FaerieMUD.org>
parents:
2
diff
changeset
|
20 |
* and/or other materials provided with the distribution. |
0 | 21 |
* |
5
41a1542b3b10
Cleaned up bsdjail extension code a bit more and made the extconf check for
Michael Granger <ged@FaerieMUD.org>
parents:
2
diff
changeset
|
22 |
* * Neither the name of the author/s, nor the names of the project's |
41a1542b3b10
Cleaned up bsdjail extension code a bit more and made the extconf check for
Michael Granger <ged@FaerieMUD.org>
parents:
2
diff
changeset
|
23 |
* contributors may be used to endorse or promote products derived from this |
41a1542b3b10
Cleaned up bsdjail extension code a bit more and made the extconf check for
Michael Granger <ged@FaerieMUD.org>
parents:
2
diff
changeset
|
24 |
* software without specific prior written permission. |
41a1542b3b10
Cleaned up bsdjail extension code a bit more and made the extconf check for
Michael Granger <ged@FaerieMUD.org>
parents:
2
diff
changeset
|
25 |
* |
41a1542b3b10
Cleaned up bsdjail extension code a bit more and made the extconf check for
Michael Granger <ged@FaerieMUD.org>
parents:
2
diff
changeset
|
26 |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
41a1542b3b10
Cleaned up bsdjail extension code a bit more and made the extconf check for
Michael Granger <ged@FaerieMUD.org>
parents:
2
diff
changeset
|
27 |
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
41a1542b3b10
Cleaned up bsdjail extension code a bit more and made the extconf check for
Michael Granger <ged@FaerieMUD.org>
parents:
2
diff
changeset
|
28 |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
41a1542b3b10
Cleaned up bsdjail extension code a bit more and made the extconf check for
Michael Granger <ged@FaerieMUD.org>
parents:
2
diff
changeset
|
29 |
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE |
41a1542b3b10
Cleaned up bsdjail extension code a bit more and made the extconf check for
Michael Granger <ged@FaerieMUD.org>
parents:
2
diff
changeset
|
30 |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
41a1542b3b10
Cleaned up bsdjail extension code a bit more and made the extconf check for
Michael Granger <ged@FaerieMUD.org>
parents:
2
diff
changeset
|
31 |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
41a1542b3b10
Cleaned up bsdjail extension code a bit more and made the extconf check for
Michael Granger <ged@FaerieMUD.org>
parents:
2
diff
changeset
|
32 |
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
41a1542b3b10
Cleaned up bsdjail extension code a bit more and made the extconf check for
Michael Granger <ged@FaerieMUD.org>
parents:
2
diff
changeset
|
33 |
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
41a1542b3b10
Cleaned up bsdjail extension code a bit more and made the extconf check for
Michael Granger <ged@FaerieMUD.org>
parents:
2
diff
changeset
|
34 |
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
41a1542b3b10
Cleaned up bsdjail extension code a bit more and made the extconf check for
Michael Granger <ged@FaerieMUD.org>
parents:
2
diff
changeset
|
35 |
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
0 | 36 |
* |
37 |
*/ |
|
38 |
||
5
41a1542b3b10
Cleaned up bsdjail extension code a bit more and made the extconf check for
Michael Granger <ged@FaerieMUD.org>
parents:
2
diff
changeset
|
39 |
#include "bsdjail.h" |
0 | 40 |
|
41 |
VALUE rbjail_mBSD; |
|
42 |
VALUE rbjail_cBSDJail; |
|
43 |
||
44 |
||
45 |
/* |
|
2 | 46 |
* Debug logging function |
47 |
*/ |
|
48 |
void |
|
49 |
#ifdef HAVE_STDARG_PROTOTYPES |
|
5
41a1542b3b10
Cleaned up bsdjail extension code a bit more and made the extconf check for
Michael Granger <ged@FaerieMUD.org>
parents:
2
diff
changeset
|
50 |
rbjail_debug(const char *fmt, ...) |
2 | 51 |
#else |
5
41a1542b3b10
Cleaned up bsdjail extension code a bit more and made the extconf check for
Michael Granger <ged@FaerieMUD.org>
parents:
2
diff
changeset
|
52 |
rbjail_debug( const char *fmt, va_dcl ) |
2 | 53 |
#endif |
54 |
{ |
|
55 |
char buf[BUFSIZ], buf2[BUFSIZ]; |
|
56 |
va_list args; |
|
57 |
||
58 |
if ( !RTEST(ruby_debug) ) return; |
|
59 |
||
5
41a1542b3b10
Cleaned up bsdjail extension code a bit more and made the extconf check for
Michael Granger <ged@FaerieMUD.org>
parents:
2
diff
changeset
|
60 |
snprintf( buf, BUFSIZ, "Debug>>> %s", fmt ); |
2 | 61 |
|
62 |
va_init_list( args, fmt ); |
|
63 |
vsnprintf( buf2, BUFSIZ, buf, args ); |
|
64 |
fputs( buf2, stderr ); |
|
65 |
fputs( "\n", stderr ); |
|
66 |
fflush( stderr ); |
|
67 |
va_end( args ); |
|
68 |
} |
|
69 |
||
70 |
||
71 |
/* |
|
0 | 72 |
struct jail { |
73 |
u_int32_t version; |
|
74 |
char *path; |
|
75 |
char *hostname; |
|
76 |
u_int32_t ip_number; |
|
77 |
}; |
|
78 |
*/ |
|
79 |
||
80 |
/* |
|
81 |
* Allocation function |
|
82 |
*/ |
|
83 |
static jail * |
|
2 | 84 |
rbjail_jail_alloc() { |
0 | 85 |
jail *ptr = ALLOC( jail ); |
86 |
||
87 |
ptr->version = 0; |
|
88 |
ptr->path = NULL; |
|
89 |
ptr->hostname = NULL; |
|
90 |
ptr->ip_number = 0; |
|
91 |
||
92 |
debugMsg(( "Initialized a jail pointer <%p>", ptr )); |
|
93 |
return ptr; |
|
94 |
} |
|
95 |
||
96 |
||
97 |
/* |
|
98 |
* GC Free function |
|
99 |
*/ |
|
100 |
static void |
|
2 | 101 |
rbjail_gc_free( jail *ptr ) { |
0 | 102 |
if ( ptr ) { |
2 | 103 |
if ( ptr->path ) xfree( ptr->path ); |
104 |
if ( ptr->hostname ) xfree( ptr->hostname ); |
|
105 |
||
0 | 106 |
ptr->path = NULL; |
107 |
ptr->hostname = NULL; |
|
2 | 108 |
|
0 | 109 |
xfree( ptr ); |
110 |
} |
|
111 |
||
112 |
else { |
|
2 | 113 |
debugMsg(( "Not freeing an uninitialized jail" )); |
0 | 114 |
} |
115 |
} |
|
116 |
||
117 |
||
118 |
/* |
|
119 |
* Object validity checker. Returns the data pointer. |
|
120 |
*/ |
|
2 | 121 |
static jail * |
122 |
rbjail_check_jail( VALUE self ) { |
|
123 |
debugMsg(( "Checking a BSD::Jail object (%d).", self )); |
|
0 | 124 |
Check_Type( self, T_DATA ); |
125 |
||
2 | 126 |
if ( !rb_obj_is_kind_of(self, rbjail_cBSDJail) ) { |
127 |
rb_raise( rb_eTypeError, "wrong argument type %s (expected BSD::Jail)", |
|
0 | 128 |
rb_class2name(CLASS_OF( self )) ); |
129 |
} |
|
130 |
||
131 |
return DATA_PTR( self ); |
|
132 |
} |
|
133 |
||
134 |
||
135 |
/* |
|
136 |
* Fetch the data pointer and check it for sanity. |
|
137 |
*/ |
|
2 | 138 |
static jail * |
139 |
rbjail_get_jail( VALUE self ) { |
|
140 |
jail *ptr = check_sentence( self ); |
|
0 | 141 |
|
2 | 142 |
debugMsg(( "Fetching a Jail (%p).", ptr )); |
0 | 143 |
if ( !ptr ) |
144 |
rb_raise( rb_eRuntimeError, "uninitialized Sentence" ); |
|
145 |
||
146 |
return ptr; |
|
147 |
} |
|
148 |
||
149 |
||
2 | 150 |
/* -------------------------------------------------------------- |
151 |
* Jail utility functions |
|
152 |
* -------------------------------------------------------------- */ |
|
153 |
||
0 | 154 |
/* |
2 | 155 |
* Try to jail_attach() to the specified +jid+, raising an exception if it fails. |
0 | 156 |
*/ |
157 |
static void |
|
158 |
rbjail_do_jail_attach( int jid ) |
|
159 |
{ |
|
160 |
if ( jail_attach(jid) == -1 ) |
|
161 |
rb_sys_fail( "jail_attach" ); |
|
162 |
} |
|
163 |
||
2 | 164 |
|
165 |
/* |
|
166 |
* Fork + Block function for rbjail_attach(). Mostly stolen from Ruby's process.c. |
|
167 |
*/ |
|
0 | 168 |
static VALUE |
169 |
rbjail_attach_block( int jid ) |
|
170 |
{ |
|
171 |
int pid; |
|
172 |
||
173 |
rb_secure(2); |
|
174 |
||
2 | 175 |
fflush( stdout ); |
176 |
fflush( stderr ); |
|
0 | 177 |
|
178 |
switch ( pid = fork() ) { |
|
179 |
case 0: |
|
180 |
rb_thread_atfork(); |
|
181 |
if ( rb_block_given_p() ) { |
|
182 |
int status; |
|
183 |
||
184 |
rbjail_do_jail_attach( jid ); |
|
185 |
rb_protect( rb_yield, Qundef, &status ); |
|
186 |
ruby_stop( status ); |
|
187 |
} |
|
188 |
return Qnil; |
|
189 |
||
190 |
case -1: |
|
191 |
rb_sys_fail( "fork(2)" ); |
|
192 |
return Qnil; |
|
193 |
||
194 |
default: |
|
195 |
return INT2FIX( pid ); |
|
196 |
} |
|
197 |
} |
|
198 |
||
2 | 199 |
|
200 |
/* -------------------------------------------------------------- |
|
201 |
* Class methods |
|
202 |
* -------------------------------------------------------------- */ |
|
203 |
||
204 |
/* |
|
205 |
* call-seq: |
|
206 |
* BSD::Jail.allocate -> bsdjail |
|
207 |
* |
|
208 |
* Allocate a new BSD::Jail object. |
|
209 |
* |
|
210 |
*/ |
|
0 | 211 |
static VALUE |
2 | 212 |
rbjail_jail_s_allocate( VALUE klass ) { |
213 |
return Data_Wrap_Struct( klass, 0, rbjail_gc_free, 0 ); |
|
214 |
} |
|
215 |
||
216 |
||
217 |
/* |
|
218 |
* call-seq: |
|
219 |
* BSD::Jail.list -> array |
|
220 |
* |
|
221 |
* Return an Array of all the running jails on the host. |
|
222 |
* |
|
223 |
*/ |
|
224 |
static VALUE |
|
225 |
rbjail_jail_s_list( VALUE klass ) { |
|
226 |
VALUE rval = rb_ary_new(); |
|
227 |
struct xprison *xp; |
|
228 |
struct in_addr in; |
|
229 |
size_t i, len; |
|
230 |
||
231 |
if ( sysctlbyname("jail.list", NULL, &len, NULL, 0) == -1 ) |
|
232 |
rb_sys_fail( "sysctlbyname(): jail.list" ); |
|
233 |
||
234 |
xp = ALLOCA_N( xprison, 1 ); |
|
235 |
||
236 |
if ( sysctlbyname("jail.list", xp, &len, NULL, 0) == -1 ) { |
|
237 |
rb_sys_fail( "sysctlbyname(): jail.list" ); |
|
238 |
} |
|
239 |
||
240 |
if ( len < sizeof(*xp) || len % sizeof(*xp) || |
|
241 |
xp->pr_version != KINFO_PRISON_VERSION ) |
|
242 |
rb_fatal( "Kernel and userland out of sync" ); |
|
243 |
||
244 |
len /= sizeof( *xp ); |
|
245 |
for ( i = 0; i < len; i++ ) { |
|
246 |
VALUE jail, args[3]; |
|
247 |
||
248 |
/* Hostname */ |
|
249 |
args[0] = rb_str_new2( xp->pr_host ); |
|
250 |
||
251 |
/* IP */ |
|
252 |
in.s_addr = ntohl( xp->pr_ip ); |
|
253 |
args[1] = rb_str_new2( inet_ntoa(in) ); |
|
254 |
||
255 |
/* Path */ |
|
256 |
args[2] = rb_str_new2( xp->pr_path ); |
|
257 |
||
258 |
jail = rb_class_new_instance( 3, args, klass ); |
|
259 |
rb_ary_push( rval, jail ); |
|
260 |
||
261 |
xp++; |
|
262 |
} |
|
263 |
||
264 |
return rval; |
|
265 |
} |
|
266 |
||
267 |
||
268 |
||
269 |
||
270 |
/* -------------------------------------------------------------- |
|
271 |
* Instance methods |
|
272 |
* -------------------------------------------------------------- */ |
|
273 |
||
274 |
/* |
|
275 |
* call-seq: |
|
276 |
* BSD::Jail.new( hostname, ip, path ) -> new_jail |
|
277 |
* |
|
278 |
* Create a new jail for the given +hostname+, +ip+, and +path+. |
|
279 |
*/ |
|
280 |
static VALUE |
|
281 |
rbjail_jail_initialize( VALUE self, VALUE hostname, VALUE ip, VALUE path ) { |
|
282 |
if ( !rbjail_check_jail(self) ) { |
|
283 |
struct jail *ptr = rbjail_jail_alloc(); |
|
284 |
char *pathstr = NULL, *hostnamestr = NULL; |
|
285 |
||
286 |
Check_Type( hostname, T_STRING ); |
|
287 |
Check_Type( ip, T_STRING ); |
|
288 |
||
289 |
pathstr = ALLOC_N( char, RSTRING(path)->len ); |
|
290 |
strncpy( pathstr, RSTRING(path)->ptr, RSTRING(path)->len ); |
|
291 |
||
292 |
hostnamestr = ALLOC_N( char, RSTRING(hostname)->len ); |
|
293 |
strncpy( hostnamestr, RSTRING(hostname)->ptr, RSTRING(hostname)->len ); |
|
294 |
||
295 |
/* |
|
296 |
struct jail { |
|
297 |
u_int32_t version; |
|
298 |
char *path; |
|
299 |
char *hostname; |
|
300 |
u_int32_t ip_number; |
|
301 |
}; |
|
302 |
*/ |
|
303 |
ptr->version = 0; /* Per the manpage's recommendation */ |
|
304 |
ptr->ip_number = inet_addr( StringValuePtr(ip) ); |
|
305 |
ptr->path = path; |
|
306 |
ptr->hostname = hostname; |
|
307 |
} |
|
308 |
} |
|
309 |
||
310 |
||
311 |
/* |
|
312 |
* call-seq: |
|
313 |
* jail.attach -> true or false |
|
314 |
* jail.attach { block } -> pid |
|
315 |
* |
|
316 |
* Attach to the given jail. In the non-block form, attach the current process to the |
|
317 |
* jail and return +true+ if it succeeds. This is a one-way operation, and requires root |
|
318 |
* privileges. |
|
319 |
* |
|
320 |
* In the block form, the process will be forked, and the block will be attached to the jail and |
|
321 |
* run by the child. The parent process will receive the process ID of the child. |
|
322 |
*/ |
|
323 |
static VALUE |
|
324 |
rbjail_attach( int argc, VALUE *argv, VALUE self ) { |
|
0 | 325 |
VALUE jidnum, rval; |
326 |
int jid; |
|
327 |
||
328 |
rb_scan_args( argc, argv, "1", &jidnum ); |
|
329 |
jid = NUM2INT( jidnum ); |
|
330 |
||
331 |
if ( rb_block_given_p() ) { |
|
332 |
rval = rbjail_attach_block( jid ); |
|
333 |
} |
|
334 |
||
335 |
else { |
|
336 |
rbjail_do_jail_attach( jid ); |
|
337 |
rval = Qtrue; |
|
338 |
} |
|
339 |
||
340 |
return rval; |
|
341 |
} |
|
342 |
||
343 |
||
2 | 344 |
/* |
345 |
* I can't remember how the hell you document a class, but that will go here. |
|
346 |
*/ |
|
0 | 347 |
void |
2 | 348 |
Init_bsdjail( void ) { |
0 | 349 |
rbjail_mBSD = rb_define_module( "BSD" ); |
350 |
rbjail_cBSDJail = rb_define_class_under( rbjail_mBSD, "Jail" ); |
|
351 |
||
2 | 352 |
/* Class methods */ |
353 |
rb_define_alloc_function( rbjail_cBSDJail, rbjail_jail_s_allocate ); |
|
354 |
rb_define_singleton_method( rbjail_cBSDJail, "jail", rbjail_jail_s_jail, 0 ); |
|
355 |
rb_define_singleton_method( rbjail_cBSDJail, "list", rbjail_jail_s_list, 0 ); |
|
0 | 356 |
|
2 | 357 |
/* Instance methods */ |
358 |
rb_define_method( rbjail_cBSDJail, "initialize", rbjail_jail_initialize, 3 ); |
|
359 |
rb_define_method( rbjail_cBSDJail, "attach", rbjail_jail_attach, -1 ); |
|
360 |
rb_define_method( rbjail_cBSDJail, "hostname", rbjail_jail_hostname, 0 ); |
|
361 |
rb_define_method( rbjail_cBSDJail, "path", rbjail_jail_path, 0 ); |
|
362 |
rb_define_method( rbjail_cBSDJail, "ip", rbjail_jail_ip, 0 ); |
|
363 |
rb_define_method( rbjail_cBSDJail, "jid", rbjail_jail_jid, 0 ); |
|
0 | 364 |
|
365 |
} |
|
366 |