File: site.py

package info (click to toggle)
sshproxy 0.6.0~beta2-2
  • links: PTS, VCS
  • area: main
  • in suites: lenny
  • size: 956 kB
  • ctags: 1,296
  • sloc: python: 8,932; sh: 268; sql: 40; makefile: 38; xml: 21
file content (286 lines) | stat: -rw-r--r-- 10,209 bytes parent folder | download
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
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
#!/usr/bin/env python
# -*- coding: ISO-8859-15 -*-
#
# Copyright (C) 2005-2007 David Guerizec <david@guerizec.net>
#
# Last modified: 2007 Dec 09, 04:02:36 by david
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA

from sshproxy.acl import ACLRule
from sshproxy.site import SiteDB, SiteInfo

from config import MySQLConfigSection
from mysql import MySQLDB, Q

class MySQLSiteConfigSection(MySQLConfigSection):
    section_id = 'site_db.mysql'

MySQLSiteConfigSection.register()


class MySQLSiteInfo(SiteInfo, MySQLDB):
    _db_handler = 'site_db'
    def __reginit__(self, login, name, **kw):
        self.open_db()
        self._sid = 0
        self._lid = 0
        SiteInfo.__reginit__(self, login, name, **kw)

    def load(self):
        query = """select id, name, ip_address, port from site
                                        where name = '%s'""" % Q(self.name)
        site = self.sql_get(query)
        if not site:
            return
        self._sid, name, ip_address, port = site

        query = """select tag, value from acltags where object = 'site'
                                                and id = %d""" % self._sid
        tags = {}
        for tag, value in self.sql_list(query):
            tags[tag] = value

        self.s_tokens.update(tags)

        tags = {'name': name, 'ip_address': ip_address, 'port': port}
        self.s_tokens.update(tags)

        # TODO: handle the default case, see also in file backend
        query = """select id, login, password, pkey, priority from login
                    where site_id = %d and ('%s' = 'None' or '%s' = login)
                    order by priority desc""" % (self._sid, Q(self.login),
                                                Q(self.login))

        login = self.sql_get(query)
        if login:
        
            self._lid, login, password, pkey, priority = login

            tags = {'login': login, 'password': password,
                    'priority': priority, 'pkey': pkey}
            self.l_tokens.update(tags)

            query = """select tag, value from acltags where object = 'login'
                                                    and id = %d""" % self._lid
            tags = {}
            for tag, value in self.sql_list(query):
                tags[tag] = value

            self.l_tokens.update(tags)

        self.loaded = True


    def save(self):
        sid = self._sid
        if sid is None:
            return

        if not self.login:
            tok = self.s_tokens
            self.sql_set('site',
                    **{'id': sid,
                       'name': self.name,
                       'ip_address': tok.get('ip_address', ''),
                       'port': tok.get('port', '22'),
                       })
            for tag, value in self.s_tokens.items():
                if tag in ('name', 'ip_address', 'port'):
                    continue
                elif value and len(str(value)):
                    self.sql_set('acltags', **{'object': 'site', 'id': sid,
                                           'tag': tag, 'value': str(value)})
                else:
                    query = ("delete from acltags where object = 'site'"
                             " and id = %d and tag = '%s'" % (sid, Q(tag)))
                    self.sql_del(query)
        
        else:
            lid = self._lid
            if not lid:
                return
    
            tok = self.l_tokens
            self.sql_set('login',
                    **{'id': lid,
                       'site_id': sid,
                       'login': self.login,
                       'password': tok.get('password', ''),
                       'pkey': tok.get('pkey', ''),
                       'priority': tok.get('priority', ''),
                       })
            for tag, value in self.l_tokens.items():
                if tag in ('name', 'login', 'password', 'pkey', 'priority'):
                    continue
                elif value and len(str(value)):
                    self.sql_set('acltags', **{'object': 'login', 'id': lid,
                                           'tag': tag, 'value': str(value)})
                else:
                    query = ("delete from acltags where object = 'login'"
                             " and id = %d and tag = '%s'" % (lid, Q(tag)))
                    self.sql_del(query)


class MySQLSiteDB(SiteDB, MySQLDB):
    _db_handler = 'site_db'
    def __reginit__(self, **kw):
        self.open_db()
        SiteDB.__reginit__(self, **kw)

    def list_site_users(self, **tokens):
        sites = []
        query = """select id, name from site order by name"""
        for id, name in self.sql_list(query):
            query = """select login from login where site_id = %d 
                                order by priority desc""" % id
            logins = []
            for (login,) in self.sql_list(query):
                logins.append(SiteInfo(login, name))

            if not len(logins):
                logins.append(SiteInfo('ORPHAN', name, priority=0))

            sites += logins

        filter = tokens.get('filter', tokens.get('f', None))
        if filter:
            siteinfos = []
            for site in sites:
                if ACLRule('list_site_users_filter',
                            filter).eval(namespace={'site':site.get_tags()}):
                    siteinfos.append(site)

            sites = siteinfos

        return sites

    def exists(self, sitename, **tokens):
        login, site = self.split_user_site(sitename)

        if login == '*':
            login = None

        query = "select id from site where name = '%s'" % Q(site)
        id = self.sql_get(query)
        if not id:
            return False

        if not login:
            return id

        query = "select id from login where login = '%s' and site_id = %d"
        id = self.sql_get(query % (Q(login), id))

        return id or False

    def add_site(self, sitename, **tokens):
        login, site = self.split_user_site(sitename)

        if login == '*':
            return "'*' is not allowed, be more specific."

        if not login:
            if self.exists(site, **tokens):
                return 'Site %s does already exist' % site
            # create site
            port = tokens.get('port', 22)
            try:
                port = int(port)
                if not (0 < port < 65536):
                    raise ValueError
            except ValueError:
                return ('Port must be numeric and have a strictly positive '
                        'value inferior to 65536')

            query = ("insert into site (name, ip_address, port) "
                               "values ('%s', '%s', '%s')")
            sid = self.sql_add(query % (Q(site),
                                       Q(tokens.get('ip_address', '')),
                                       port))
            if not sid:
                return 'A problem occured when adding site %s' % sitename

        elif not self.exists(site, **tokens):
            # if site does not exist and a login was given, exit with an error
            return 'Please create site %s first' % site
        
        else:
            if self.exists(sitename, **tokens):
                return 'Site %s does already exist' % sitename

            sid = self.sql_get("select id from site where name = '%s'"
                                                                    % Q(site))
            query = ("insert into login (site_id, login, password) "
                               "values (%d, '%s', '%s')")
            lid = self.sql_add(query % (sid,
                                       Q(login),
                                       Q(tokens.get('password', ''))))
            if not lid:
                return 'A problem occured when adding site %s' % sitename

        site = SiteInfo(login, site, **tokens)
        site.save()
        return 'Site %s added' % sitename

    def _del_login(self, login_id, **tokens):
        query = "delete from acltags where object = 'login' and id = %d"
        self.sql_del(query % login_id)

        query = "delete from login where id = %d"
        self.sql_del(query % login_id)

    def del_site(self, sitename, **tokens):
        login, site = self.split_user_site(sitename)

        if login == '*':
            sitename = name

        sid = self.exists(sitename, **tokens)
        if not sid:
            return 'Site %s does not exist' % sitename

        if login:
            ret = False
            if login == '*':
                query = "select login from login where site_id = %d" % sid
                for lid in self.sql_list(query):
                    self._del_login(lid, **tokens)
                    ret = True
                sitename = '*@%s' % name

            else:
                lid = self.exists(sitename, **tokens)
                if lid:
                    self._del_login(lid, **tokens)
                    ret = True

            if not ret:
                return 'Site %s does not exist' % sitename

            return 'Site %s deleted' % sitename

        else:
            query = "select count(*) from login where site_id = %d"
            count = self.sql_get(query % sid)
            if count > 0:
                return "Site %s has still %d logins" % (sitename, count)

            query = "delete from acltags where object = 'site' and id = %d"
            self.sql_del(query % sid)

            query = "delete from site where id = %d"
            self.sql_del(query % sid)