rstyx 0.4.0 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
data/lib/rstyx/server.rb CHANGED
@@ -1,42 +1,40 @@
1
1
  #!/usr/bin/ruby
2
2
  #
3
+ # Author:: Rafael R. Sevilla (mailto:dido@imperium.ph)
4
+ # Copyright:: Copyright (c) 2005-2007 Rafael R. Sevilla
5
+ # Homepage:: http://rstyx.rubyforge.org/
6
+ # License:: GNU Lesser General Public License / Ruby License
7
+ #
8
+ # $Id: server.rb 278 2007-09-19 07:22:37Z dido $
9
+ #
10
+ #----------------------------------------------------------------------------
11
+ #
3
12
  # Copyright (C) 2005-2007 Rafael Sevilla
4
13
  # This file is part of RStyx
5
14
  #
6
- # RStyx is free software; you can redistribute it and/or modify
7
- # it under the terms of the GNU Lesser General Public License as
8
- # published by the Free Software Foundation; either version 2.1
9
- # of the License, or (at your option) any later version.
15
+ # This program is free software; you can redistribute it and/or modify
16
+ # it under the terms of either 1) the GNU Lesser General Public License
17
+ # as published by the Free Software Foundation; either version 3 of the
18
+ # License, or (at your option) any later version; or 2) Ruby's license.
10
19
  #
11
- # RStyx is distributed in the hope that it will be useful, but
12
- # WITHOUT ANY WARRANTY; without even the implied warranty of
13
- # MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
- # GNU Lesser General Public License for more details.
20
+ # See the file COPYING for complete licensing information
15
21
  #
16
- # You should have received a copy of the GNU Lesser General Public
17
- # License along with RStyx; if not, write to the Free Software
18
- # Foundation, Inc., 51 Franklin St., Fifth Floor, Boston, MA
19
- # 02110-1301 USA.
22
+ #----------------------------------------------------------------------------
20
23
  #
21
24
  # Styx Server
22
25
  #
23
26
  # To create a Styx server, one has to create an SDirectory object that
24
27
  # acts as the server root, e.g.:
25
28
  #
26
- # sd = RStyx::Server::SDirectory.new("/")
27
- # sf = RStyx::Server::InMemoryFile.new("test.file")
28
- # sf.contents = "hello"
29
- # sd << sf
30
- # serv = RStyx::Server::TCPServer.new(:bindaddr => "0.0.0.0",
31
- # :port => 9876,
32
- # :root => sd)
33
- # serv.run.join
29
+ # sd = RStyx::Server::SDirectory.new("/")
30
+ # sf = RStyx::Server::InMemoryFile.new("test.file")
31
+ # sf.contents = "hello"
32
+ # sd << sf
33
+ # serv = RStyx::Server::TCPServer.new(:bindaddr => "0.0.0.0",
34
+ # :port => 9876,
35
+ # :root => sd)
36
+ # serv.run.join
34
37
  #
35
- # Author:: Rafael R. Sevilla (mailto:dido@imperium.ph)
36
- # Copyright:: Copyright (c) 2005-2007 Rafael R. Sevilla
37
- # License:: GNU Lesser General Public License
38
- #
39
- # $Id: server.rb 249 2007-09-14 04:21:18Z dido $
40
38
  #
41
39
  require 'thread'
42
40
  require 'monitor'
@@ -59,7 +57,31 @@ module RStyx
59
57
  # assemble all inbound messages
60
58
  #
61
59
  module StyxServerProtocol
62
- attr_accessor :sentmessages, :msize, :log, :root
60
+ ##
61
+ # maximum message size supported
62
+ attr_accessor :msize
63
+ ##
64
+ # Logger object used for logging server events
65
+ attr_accessor :log
66
+ ##
67
+ # The root of the file tree for this server
68
+ attr_accessor :root
69
+ ##
70
+ # An authenticator which is sent messages received from the client.
71
+ # Used when doing Inferno authentication.
72
+ attr_accessor :authenticator
73
+ ##
74
+ # The session object corresponding to this connection
75
+ attr_accessor :session
76
+ ##
77
+ # Server's authentication information
78
+ attr_accessor :myauth
79
+ ##
80
+ # Connected peer's authentication information
81
+ attr_accessor :userauth
82
+ ##
83
+ # Shared secret obtained during Inferno authentication
84
+ attr_accessor :secret
63
85
 
64
86
  DEFAULT_MSIZE = 8216
65
87
 
@@ -95,11 +117,11 @@ module RStyx
95
117
  # negotiation results in the protocol_negotiated flag in the
96
118
  # current session becoming true, and all other outstanding I/O
97
119
  # on the session (e.g. opened fids and the like) all removed.
98
- #
120
+ #--
99
121
  # External methods used:
100
122
  #
101
123
  # Session#reset_session *
102
- #
124
+ #++
103
125
  def tversion(msg)
104
126
  @cversion = msg.version
105
127
  @cmsize = msg.msize
@@ -123,7 +145,7 @@ module RStyx
123
145
  # depending on the auth methods that we decide to support.
124
146
  #
125
147
  def tauth(msg)
126
- return(Message::Rerror.new(:ename => "Authentication methods through auth messages are not used."))
148
+ return(Message::Rerror.new(:ename => "Authentication methods through auth messages are not supported."))
127
149
  end
128
150
 
129
151
  ##
@@ -134,14 +156,14 @@ module RStyx
134
156
  # 1. The client has not done a version negotiation yet.
135
157
  # 2. The client has provided a fid which it is already using
136
158
  # for something else.
137
- #
159
+ #--
138
160
  # External methods used:
139
161
  #
140
162
  # Session#version_negotiated? *
141
163
  # Session#has_fid? *
142
164
  # Session#[]= *
143
165
  # SFile#qid (root) *
144
- #
166
+ #++
145
167
  def tattach(msg)
146
168
  # Do not allow attaches without version negotiation
147
169
  unless @session.version_negotiated?
@@ -175,11 +197,11 @@ module RStyx
175
197
  # flushed transaction). Some means, possibly a session-wide
176
198
  # global transaction lock on server internal state changes
177
199
  # may be necessary to allow flushes of this kind to work.
178
- #
200
+ #--
179
201
  # External methods used:
180
202
  #
181
203
  # Session#flush_tag *
182
- #
204
+ #++
183
205
  def tflush(msg)
184
206
  @session.flush_tag(msg.oldtag)
185
207
  return(Message::Rflush.new)
@@ -205,7 +227,7 @@ module RStyx
205
227
  # Note that if several parts of the walk managed to succeed, this
206
228
  # method will still return an Rwalk response, but it will NOT
207
229
  # associate newfid with anything.
208
- #
230
+ #--
209
231
  # External methods used:
210
232
  #
211
233
  # Session#[] *
@@ -218,7 +240,7 @@ module RStyx
218
240
  # SFile#atime=
219
241
  # SFile#[]
220
242
  # SFile#qid
221
- #
243
+ #++
222
244
  #
223
245
  def twalk(msg)
224
246
  if msg.wnames.length > MAXWELEM
@@ -232,13 +254,12 @@ module RStyx
232
254
  raise StyxException.new("cannot walk to an open fid")
233
255
  end
234
256
  nfid = msg.newfid
235
- if nfid != fid
236
- # if the original and new fids are different, check that
237
- # the new fid isn't already in use.
238
- if (@session.has_fid?(nfid))
239
- raise StyxException.new("fid already in use")
240
- end
257
+ # if the original and new fids are different, check that
258
+ # the new fid isn't already in use.
259
+ if nfid != fid && @session.has_fid?(nfid)
260
+ raise StyxException.new("fid already in use")
241
261
  end
262
+
242
263
  rwalk = Message::Rwalk.new(:qids => [])
243
264
  num = 0
244
265
  msg.wnames.each do |n|
@@ -258,6 +279,7 @@ module RStyx
258
279
  end
259
280
  break
260
281
  end
282
+ sf.atime = Time.now
261
283
  # This allows a client to get a fid representing the directory
262
284
  # at the end of the walk, even if the client does not have
263
285
  # execute permissions on that directory. Therefore, in Inferno,
@@ -279,7 +301,7 @@ module RStyx
279
301
 
280
302
  ##
281
303
  # Handle open messages.
282
- #
304
+ #--
283
305
  # External methods used:
284
306
  #
285
307
  # Session#[]
@@ -289,7 +311,7 @@ module RStyx
289
311
  # SFile#qid
290
312
  # Session#iounit
291
313
  # Session#user
292
- #
314
+ #++
293
315
  def topen(msg)
294
316
  sf = @session[msg.fid]
295
317
  mode = msg.mode
@@ -312,11 +334,38 @@ module RStyx
312
334
  unless @session.writable?(dir)
313
335
  raise StyxException.new("permission denied, no write permissions to parent directory")
314
336
  end
337
+ # Check the file type
338
+ perm = msg.perm
339
+ isdir = (perm & DMDIR) != 0
340
+ isapponly = (perm & DMAPPEND) != 0
341
+ isexclusive = (perm & DMEXCL) != 0
342
+ isauth = (perm & DMAUTH) != 0
343
+
344
+ if isauth
345
+ # Auth files cannot be created by Styx messages
346
+ raise StyxException.new("can't create a file of type DMAUTH")
347
+ end
348
+
349
+ # Get the low 9 bits of the permission number (these low 9 bits
350
+ # are the rwxrwxrwx file permissions)
351
+ operm = msg.perm & 01777
352
+ # Get the real permissions of this file. This depends on the
353
+ # permissions of the parent directory
354
+ realperm = operm
355
+ if isdir
356
+ realperm = operm & (~0777 | (dir.permissions & 0777))
357
+ # directories must be opened with OREAD (no other bits set)
358
+ if msg.mode != OREAD
359
+ raise StyxException.new("when creating a directory must open with read permission only")
360
+ end
361
+ else
362
+ realperm = operm & (~0666 | (dir.permissions & 0666))
363
+ end
315
364
 
316
- # Create the file in the directory. Note that SDirectory#newfile
317
- # has to do all of the permission checking and all that.
318
- new_file = dir.newfile(msg.name, msg.perm)
319
- o dir << new_file
365
+ # Create the file in the directory, add it to the directory tree,
366
+ # and associate the new file with the given fid
367
+ new_file = dir.newfile(msg.name, realperm, isdir, isapponly, isexcl)
368
+ dir << new_file
320
369
  @session[msg.fid] = new_file
321
370
  new_file.add_client(SFileClient.new(@session, msg.fid, msg.mode))
322
371
  return(Message::Rcreate.new(:qid => new_file.qid,
@@ -383,7 +432,7 @@ o dir << new_file
383
432
  # A remove is just like a clunk with the side effect of
384
433
  # removing the file if the permissions allow.
385
434
  sf = @session[msg.fid]
386
- sf.lock do
435
+ sf.synchronize do
387
436
  @session.clunk(msg.fid)
388
437
  parent = sf.parent
389
438
  if @session.writable?(parent)
@@ -394,8 +443,8 @@ o dir << new_file
394
443
  raise StyxException.new("directory not empty")
395
444
  end
396
445
  sf.remove
446
+ parent.set_mtime(Time.now, @session.user)
397
447
  end
398
- parent.set_mtime(Time.now, @session.user)
399
448
  return(Message::Rremove.new)
400
449
  end
401
450
 
@@ -414,7 +463,7 @@ o dir << new_file
414
463
  def twstat(msg)
415
464
  nstat = msg.stat
416
465
  sf = @session[msg.fid]
417
- sf.lock do
466
+ sf.synchronize do
418
467
  # Check if we are changing the file's name
419
468
  unless nstat.name.empty?
420
469
  dir = sf.parent
@@ -554,8 +603,10 @@ o dir << new_file
554
603
  @log.error("#{@peername} unknown fid in message #{msg.to_s}")
555
604
  reply(Message::Rerror.new(:ename => "Unknown fid #{e.fid}"), tag)
556
605
  rescue StyxException => e
557
- @log.error("#{@peername} styx exception #{e.message} in #{msg.to_s}")
606
+ @log.error("#{@peername} styx exception #{e.message} for #{msg.to_s}")
558
607
  reply(Message::Rerror.new(:ename => "Error: #{e.message}"), tag)
608
+ rescue Exception => e
609
+ @log.error("#{@peername} internal error #{e.message} for #{e.to_s} at #{e.backtrace}")
559
610
  end
560
611
 
561
612
  end
@@ -565,6 +616,12 @@ o dir << new_file
565
616
  # Receive data from the network connection, called by EventMachine.
566
617
  #
567
618
  def receive_data(data)
619
+ # If we are in keyring authentication mode, write any data received
620
+ # into the @auth's buffer, and simply return.
621
+ unless @authenticator.nil?
622
+ @authenticator << data
623
+ return
624
+ end
568
625
  @msgbuffer << data
569
626
  # self.class.log.debug(" << #{data.unpack("H*").inspect}")
570
627
  while @msgbuffer.length > 4
@@ -621,6 +678,10 @@ o dir << new_file
621
678
  # Active iounit for this connection
622
679
  #
623
680
  attr_accessor :iounit
681
+ ##
682
+ # Group table
683
+ #
684
+ attr_accessor :groups
624
685
 
625
686
  ##
626
687
  # Create a new session.
@@ -772,15 +833,17 @@ o dir << new_file
772
833
  end
773
834
  end
774
835
 
836
+ # These constants are used by Session#permission? and should NOT
837
+ # be changed. The algorithm used depends on it!
838
+ EXECUTE = 0
839
+ WRITE = 1
840
+ READ = 2
841
+
775
842
  ##
776
843
  # Check the permissions for a given mode
777
844
  #
778
- #--
779
- # FIXME: the permissions are only for anonymous access at the
780
- # moment, so only the world permissions are ever checked.
781
- #++
782
845
  # _sf_:: the file to check against
783
- # _mode_:: the mode to check (OEXEC, OWRITE, or OREAD)
846
+ # _mode_:: the mode to check (EXEC, WRITE, or READ)
784
847
  #
785
848
  def permission?(sf, mode)
786
849
  if mode < 0 || mode > 2
@@ -788,22 +851,42 @@ o dir << new_file
788
851
  end
789
852
  # We bit shift the permissions value so that the mode is
790
853
  # represented by the last bit (all) the fourth to last bit
791
- # (group), and the seventh-to-last bit (user).
854
+ # (group), and the seventh-to-last bit (user). For example,
855
+ # if we started with a mode of 0755 (binary 111101101,
856
+ # rwxrwxrwx), and we want to check write permissions, we
857
+ # shift by one bit so that the value of perms is 1110110, or
858
+ # (rwxrwxrw).
792
859
  perms = sf.permissions >> mode
793
860
  # Check permissions for 'all' -- the low-order bit
794
- if perms & 0b000_000_001 == 1
861
+ unless perms & 0b000_000_001 == 0
795
862
  return(true)
796
863
  end
797
864
 
798
- # XXX: this has to be something more useful!
799
- return(false)
865
+ # Group permissions
866
+ unless (perms & 0b000_001_000) == 0
867
+ # The group has the correct permissions; now we have to find if
868
+ # the user is a member of the group in question.
869
+ ug = @groups[@user]
870
+ unless ug.index(sf.gid).nil?
871
+ return(true)
872
+ end
873
+ end
874
+
875
+ # Owner permissions. This is the final fallback.
876
+ return(((perms & 0b001_000_000) != 0) && (@user == sf.uid))
800
877
  end
801
878
 
802
879
  ##
803
880
  # Check for executable permission for the SFile _sf_.
804
881
  #
805
882
  def execute?(sf)
806
- return(true)
883
+ return(permission?(sf, EXECUTE))
884
+ end
885
+
886
+ ##
887
+ # Check for write permission for the SFile _sf_.
888
+ def writable?(sf)
889
+ return(permission?(sf, WRITE))
807
890
  end
808
891
 
809
892
  ##
@@ -818,7 +901,59 @@ o dir << new_file
818
901
  raise StyxException.new("can't open locked file")
819
902
  end
820
903
  openmode = mode & 0x03
821
- # XXX: Needs to be filled out further...
904
+ case openmode
905
+ when OREAD
906
+ unless permission?(sf, READ)
907
+ raise StyxException.new("read permission denied")
908
+ end
909
+ when OWRITE
910
+ unless permission?(sf, WRITE)
911
+ raise StyxException.new("write permission denied")
912
+ end
913
+ when ORDWR
914
+ unless permission?(sf, READ)
915
+ raise StyxException.new("read permission denied")
916
+ end
917
+ unless permission?(sf, WRITE)
918
+ raise StyxException.new("write permission denied")
919
+ end
920
+ when OEXEC
921
+ unless permission?(sf, EXECUTE)
922
+ raise StyxException.new("execute permission denied")
923
+ end
924
+ else
925
+ # shouldn't happen
926
+ raise StyxException.new("internal Styx error openmode = #{openmode}: should be between 0 and 3")
927
+ end
928
+
929
+ # Execute permission is required for a directory in order to
930
+ # do anything with it
931
+ if sf.directory? && !execute?(sf)
932
+ raise StyxException("directory execute permission denied")
933
+ end
934
+
935
+ if (mode & OTRUNC) != 0
936
+ # can't truncate a directory
937
+ if sf.directory?
938
+ raise StyxException.new("cannot truncate a directory")
939
+ end
940
+ unless permission?(sf, WRITE)
941
+ raise StyxException.new("need write permissions to truncate a file")
942
+ end
943
+ end
944
+
945
+ if (mode & ORCLOSE) != 0
946
+ # can't delete a directory on closing
947
+ if sf.directory?
948
+ raise StyxException.new("cannot automatically delete a directory")
949
+ end
950
+ # we must have write permissions on the parent directory and the file
951
+ # itself to delete the file on clunking its fid
952
+ unless permission?(sf.parent, WRITE)
953
+ raise StyxException.new("need write permissions on the parent directory to delete the file when the fid is clunked")
954
+ end
955
+ # TODO: do we need write permissions on the file itself?
956
+ end
822
957
  end
823
958
 
824
959
  end # class Session
@@ -837,12 +972,27 @@ o dir << new_file
837
972
  # serve (typically an SDirectory instance)
838
973
  # _:log_:: A Logger object where server-generated log messages
839
974
  # are stored.
975
+ # _:auth_:: An authentication object. If this is a
976
+ # Keyring::Authinfo instance, it will use the Inferno
977
+ # authentication protocol to authenticate clients who
978
+ # connect, and only allow connections from clients with
979
+ # certificates signed by the same CA that signed its
980
+ # own certificate. If this is nil, no authentication
981
+ # will be required for connections.
982
+ # _:groups_:: A hash table, indexed by user names, that returns
983
+ # an array of groups of which a particular user is
984
+ # member of. If not specified, it defaults to an
985
+ # empty group table (which sets the group of everyone
986
+ # to 'nogroup')
840
987
  # _:debug_:: Debug level, which is assigned to the logger's level
841
988
  # Set this to Logger::DEBUG if you want full debugging
842
989
  # messages to appear.
843
990
  #
844
991
  def initialize(config)
845
992
  @root = config[:root]
993
+ @auth = config[:auth]
994
+ @groups = config[:groups]
995
+ @groups ||= Hash.new(["nogroup"])
846
996
  @log = config[:log] || Logger.new(STDERR)
847
997
  @log.level = config[:debug] || Logger::WARN
848
998
  end
@@ -898,6 +1048,51 @@ o dir << new_file
898
1048
  StyxServerProtocol) do |conn|
899
1049
  conn.root = @root
900
1050
  conn.log = @log
1051
+ if @auth.is_a?(Keyring::Authinfo)
1052
+ # Perform Inferno authentication protocol
1053
+ conn.myauth = @auth
1054
+ conn.authenticator = Keyring::FileWrapper.new(conn)
1055
+ Thread.new do
1056
+ begin
1057
+ conn.userauth, conn.secret = Keyring.auth(conn.authenticator,
1058
+ :server, @auth,
1059
+ ["none"])
1060
+ rescue Exception => e
1061
+ # You fail. Get outta my face!
1062
+ @log.info("client authentication error #{e.class.to_s}: #{e.message}")
1063
+ conn.close_connection
1064
+ else
1065
+ # Successful authentication. Set the session.auth flag to
1066
+ # true and the user to the owner of the public key that
1067
+ # was used to authenticate
1068
+ conn.session.user = conn.userauth.mypk.owner
1069
+ conn.session.auth = true
1070
+ @log.info("authenticated connection for #{conn.session.user}")
1071
+ # Stop using the authenticator after the protocol is done.
1072
+ # The authenticator might have received some data meant
1073
+ # to be Styx protocol messages so we do receive_data to
1074
+ # make sure that the data does get received.
1075
+ a = conn.authenticator
1076
+ conn.authenticator = nil
1077
+ if a.data.length > 0
1078
+ conn.receive_data(a.data)
1079
+ end
1080
+ end
1081
+ end
1082
+ else
1083
+ # Either we're using some other non-Inferno authentication
1084
+ # method, in which case auth files are used and the peer
1085
+ # authentication information is filled in later, or we're
1086
+ # not bothering to do any authentication. We fill in
1087
+ # userauth with nil (the connection is unauthenticated)
1088
+ # and we put "nobody" in the username (the anonymous user).
1089
+ conn.userauth = nil
1090
+ conn.session.user = "nobody"
1091
+ conn.session.auth = false
1092
+ conn.authenticator = nil
1093
+ @log.info("unauthenticated connection for #{conn.username}")
1094
+ end
1095
+ conn.session.groups = @groups
901
1096
  end
902
1097
  end
903
1098
  end
@@ -969,7 +1164,7 @@ o dir << new_file
969
1164
  # opened it with read access mode).
970
1165
  #
971
1166
  def readable?
972
- return(mode == OREAD || mode == ORDWR)
1167
+ return(@mode == OREAD || @mode == ORDWR)
973
1168
  end
974
1169
 
975
1170
  ##
@@ -977,7 +1172,7 @@ o dir << new_file
977
1172
  # opened it with write access).
978
1173
  #
979
1174
  def writable?
980
- return(mode == OWRITE || mode == ORDWR)
1175
+ return(@mode == OWRITE || @mode == ORDWR)
981
1176
  end
982
1177
 
983
1178
  end
@@ -1473,7 +1668,7 @@ o dir << new_file
1473
1668
  # implementation does nothing; subclasses must override this to
1474
1669
  # provide the correct functionality.
1475
1670
  #
1476
- def refresh
1671
+ def refresh(update_children)
1477
1672
  end
1478
1673
  end # class SFile
1479
1674
 
@@ -1608,10 +1803,17 @@ o dir << new_file
1608
1803
  # FIXME: make this method actually DO something!
1609
1804
  #++
1610
1805
  #
1611
- def newfile(name, perm)
1806
+ def newfile(name, perm, isdir, isapponly, isexcl)
1612
1807
  raise StyxException.new("cannot create files in this directory")
1613
1808
  end
1614
1809
 
1810
+ ##
1811
+ # Remove a file from the directory
1812
+ def remove_child(child)
1813
+ @children.delete(child)
1814
+ self.contents_changed
1815
+ end
1816
+
1615
1817
  end # class SDirectory
1616
1818
 
1617
1819
  ##
data/lib/rstyx/version.rb CHANGED
@@ -1,34 +1,35 @@
1
1
  #!/usr/bin/ruby
2
2
  #
3
- # Copyright (C) 2005 Rafael Sevilla
3
+ # Author:: Rafael R. Sevilla (mailto:dido@imperium.ph)
4
+ # Copyright:: Copyright (c) 2005-2007 Rafael R. Sevilla
5
+ # Homepage:: http://rstyx.rubyforge.org/
6
+ # License:: GNU Lesser General Public License / Ruby License
7
+ #
8
+ # $Id: version.rb 285 2007-09-19 07:32:56Z dido $
9
+ #
10
+ #----------------------------------------------------------------------------
11
+ #
12
+ # Copyright (C) 2005-2007 Rafael Sevilla
4
13
  # This file is part of RStyx
5
14
  #
6
- # RStyx is free software; you can redistribute it and/or modify
7
- # it under the terms of the GNU Lesser General Public License as
8
- # published by the Free Software Foundation; either version 2.1
9
- # of the License, or (at your option) any later version.
15
+ # This program is free software; you can redistribute it and/or modify
16
+ # it under the terms of either 1) the GNU Lesser General Public License
17
+ # as published by the Free Software Foundation; either version 3 of the
18
+ # License, or (at your option) any later version; or 2) Ruby's license.
10
19
  #
11
- # RStyx is distributed in the hope that it will be useful, but
12
- # WITHOUT ANY WARRANTY; without even the implied warranty of
13
- # MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
- # GNU Lesser General Public License for more details.
20
+ # See the file COPYING for complete licensing information
15
21
  #
16
- # You should have received a copy of the GNU Lesser General Public
17
- # License along with RStyx; if not, write to the Free Software
18
- # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19
- # 02111-1307 USA.
22
+ #----------------------------------------------------------------------------
20
23
  #
21
24
  # RStyx version code
22
25
  #
23
- # $Id: version.rb 261 2007-09-18 04:43:42Z dido $
24
- #
25
26
 
26
27
  module RStyx
27
28
  module Version
28
29
 
29
30
  MAJOR = 0
30
31
  MINOR = 4
31
- TINY = 0
32
+ TINY = 1
32
33
 
33
34
  # The version of RStyx in use.
34
35
  STRING = [ MAJOR, MINOR, TINY ].join(".")
data/lib/rstyx.rb CHANGED
@@ -1,31 +1,33 @@
1
1
  #!/usr/bin/ruby
2
2
  #
3
- # Copyright (C) 2005,2006 Rafael Sevilla
3
+ # Author:: Rafael R. Sevilla (mailto:dido@imperium.ph)
4
+ # Copyright:: Copyright (c) 2005-2007 Rafael R. Sevilla
5
+ # Homepage:: http://rstyx.rubyforge.org/
6
+ # License:: GNU Lesser General Public License / Ruby License
7
+ #
8
+ # $Id: rstyx.rb 294 2007-09-19 07:45:28Z dido $
9
+ #
10
+ #----------------------------------------------------------------------------
11
+ #
12
+ # Copyright (C) 2005-2007 Rafael Sevilla
4
13
  # This file is part of RStyx
5
14
  #
6
- # RStyx is free software; you can redistribute it and/or modify
7
- # it under the terms of the GNU Lesser General Public License as
8
- # published by the Free Software Foundation; either version 2.1
9
- # of the License, or (at your option) any later version.
15
+ # This program is free software; you can redistribute it and/or modify
16
+ # it under the terms of either 1) the GNU Lesser General Public License
17
+ # as published by the Free Software Foundation; either version 3 of the
18
+ # License, or (at your option) any later version; or 2) Ruby's license.
10
19
  #
11
- # RStyx is distributed in the hope that it will be useful, but
12
- # WITHOUT ANY WARRANTY; without even the implied warranty of
13
- # MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
- # GNU Lesser General Public License for more details.
20
+ # See the file COPYING for complete licensing information
15
21
  #
16
- # You should have received a copy of the GNU Lesser General Public
17
- # License along with RStyx; if not, write to the Free Software
18
- # Foundation, Inc., 51 Franklin St., Fifth Floor, Boston, MA
19
- # 02110-1301 USA.
22
+ #----------------------------------------------------------------------------
20
23
  #
21
24
  # Main require -- should get everything ready for the user of the lib.
22
25
  #
23
- # $Id: rstyx.rb 260 2007-09-18 04:43:12Z dido $
24
26
  #
25
27
  require 'rstyx/common'
26
28
  require 'rstyx/messages'
27
29
  require 'rstyx/errors'
28
30
  require 'rstyx/keyring'
29
31
  require 'rstyx/client'
30
- require 'rstyx/authmodules'
32
+ require 'rstyx/server'
31
33