-
Notifications
You must be signed in to change notification settings - Fork 1
/
arpa2cmd.py
186 lines (152 loc) · 5.22 KB
/
arpa2cmd.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# arpa2cmd is a base class for ARPA2 command interpreters.
# It shows itself as arpa2shell, from which it usually runs.
#
# These interpreters can be told to know_about each other
# and call each other when combined with the meta-shell of
# the bare instance below.
#
# From: Rick van Rein <rick@openfortress.nl>
import sys
import time
import cmd
from cmdparser import cmdparser
import types
@cmdparser.CmdClassDecorator()
class Cmd (cmd.Cmd):
version = (0,0)
prompt = 'arpa2shell> '
intro = 'The ARPA2 generic command shell offers basic support to actual shells.'
gss_name = None
gss_life = None
"""General class for switching between shells.
It relies on do_arpa2xxx functions in each and
shares such commands for allowing switches at
termination of the calling shell. These
functions therefore usually just return True
after setting the next shell name. This is
even safe for references to the shell itself,
except in the case of ARPA2shell which has none
above it.
"""
def __init__ (self, *args, **kwargs):
cmd.Cmd.__init__ (self, *args, **kwargs)
self.known = [ ]
self.next_shell = None
def reset (self):
"""Actual shells should override the reset
method such that they remove traces of
command history. This is an abstract
method, so don't bother calling it from
the subclass.
"""
raise NotImplementedError ('No reset method for this shell')
@cmdparser.CmdMethodDecorator()
def do_help (self, args, fields):
"""help [<cmd>]
Trigger the help command in the superclass, but apply
the cmdparser wrapper so it can be called over JSON.
There is a shorthand notation, namely a question mark.
"""
cmd.Cmd.do_help (self, ' '.join (args [1:]))
@cmdparser.CmdMethodDecorator()
def do_version (self, *ignored):
"""version
Print the name and current version of this shell.
"""
sys.stdout.write ('%s-%d.%d\n' % (self.prompt.split ('>') [0], self.version [0], self.version [1]))
return False
@cmdparser.CmdMethodDecorator()
def do_ping (self, *ignored):
"""ping
Respond to ping requests (with output on stderr).
"""
sys.stderr.write ('EPROTONOSUPPORT: Please upgrade to ping6\n')
return False
@cmdparser.CmdMethodDecorator()
def do_ping6 (self, *ignored):
"""ping6
Respond to ping6 requests (with output on stdout).
"""
sys.stdout.write ('pong6\n')
return False
@cmdparser.CmdMethodDecorator()
def do_date (self, *ignored):
"""date
Request the current time on the system running the shell.
"""
sys.stdout.write ('%s\n' % time.asctime (time.gmtime ()))
return False
@cmdparser.CmdMethodDecorator()
def do_whoami (self, *ignored):
"""whoami
Ask who you are, and how the shell sees you during ACL processing.
"""
if self.gss_name is None or self.gss_life is None:
sys.stderr.write ('You are nobody\n')
return False
try:
import gssapi
except ImportError as ie:
sys.stderr.write ('This shell does not support GSSAPI\n')
return False
try:
exp = time.asctime (time.gmtime (self.gss_life))
sys.stdout.write ('You are: %s\nExpiration: %s\n' % (self.gss_name,exp))
except gssapi.raw.MissingCredentialsError:
sys.stderr.write ('You are nobody\n')
except gssapi.raw.ExpiredCredentialsError:
sys.stderr.write ('You have expired\n')
except gssapi.raw.InvalidCredentialsError:
sys.stderr.write ('Your credentials are wrong\n')
except gssapi.raw.GSSError as ge:
sys.stderr.write ('GSSAPI Error: %s\n' % str (ge))
except Exception as e:
sys.stderr.write ('General error: %s\n' % str (e))
return False
"""Termination commands. No JSON wrappers.
"""
def do_EOF (self, *ignored):
"""Exit this shell.
"""
return True
do_exit = do_EOF
do_quit = do_EOF
"""Switch to the main command loop for arpa2shell.
"""
# def do_arpa2shell (self, *ignored):
# # Special case: no shell above this one
# return False
"""Bind a shell to self, and make it return the
provided module as the shell to switch to.
"""
def bound_shell (self, name, module):
def switch_shell (self, *ignored):
self.next_shell = module
return True
switch_shell.__doc__ = 'Switch to the ' + name + ' shell: ' + module.intro
return switch_shell
"""Add a shell object by introducing it to all
the shells that we already know about. This
transitively installs do_arpa2xxx functions
that return True after setting next_shell.
Think of this function as joining two sets by
pairing all pairs from the two sets, in one
direction only; it is explicitly repeated in
both directions between the two sets so as to
avoid infinite recursion.
It is assumed that at least on instance is a
mere ARPA2shell without subclass. This one
can then be called to "just" be able to step
into any of the other shells. This is not a
necessity, however.
"""
def know_about (self, shellname, shellobj):
if (shellname,shellobj) not in self.known:
self.known.append ( (shellname,shellobj) )
for (knownname,knownobj) in self.known:
knownobj.know_about (shellname, shellobj)
bound_switch = self.bound_shell (shellname, shellobj)
self.__class__.__dict__ ['do_' + shellname] = bound_switch
if __name__ == '__main__':
shell = Cmd ()
shell.cmdloop ()