Comments 56
А колеса-то у Вас квадратные linux.die.net/man/8/pure-ftpd :)
Юзеры в MySQL. Месье знает толк в извращениях.
Базу можно подобрать под себя любую.
Why not?
Я вот не вижу каких-то однозначных причин не использовать mysql для этих целей.
Другое дело пароли в открытом виде, но и для этого могут быть причины.
Я вот не вижу каких-то однозначных причин не использовать mysql для этих целей.
Другое дело пароли в открытом виде, но и для этого могут быть причины.
а кто мешает хранить их в MD5?
Можно сказать, что это прототип.
Можно сказать, что это прототип.
да конечно не что не мешает.
это я написал в тему, что уж если хочется придраться, то лучше к этому чем к mysql — тут хоть какую-то причину придумать можно
это я написал в тему, что уж если хочется придраться, то лучше к этому чем к mysql — тут хоть какую-то причину придумать можно
Иногда нужно интегрировать FTP с существующей базой пользователей на Mysql или другой. В этом случае проще использовать СУБД напрямую чем через md5/sqllite
А кто сказал что mySQL не подходит. Гвозди тоже можно микроскопом забивать. А какие у mySQL преимущества перед другими бд для хранения паролей?
зависит от условий
пускай юзеров 100 000 и они пытаются поддерживать фтп соединение по фиговым каналам. лучше в plain text хранить?
а если учесть что на сервере скорее всего уже стоит mysql, то чем лучше тот sqlite или plain text?
в каком месте myisam на микроскоп для гвоздей похож?
пускай юзеров 100 000 и они пытаются поддерживать фтп соединение по фиговым каналам. лучше в plain text хранить?
а если учесть что на сервере скорее всего уже стоит mysql, то чем лучше тот sqlite или plain text?
в каком месте myisam на микроскоп для гвоздей похож?
Чем mySQL лучше других БД для хранения паролей? И какая разница сколько юзеров?
А чем хуже?
MySQL — реляционная СУБД. Зачем к примеру вам для хранения паролей все плюшки mySQL? Это и есть забивание гвоздей микроскопом. Или вы считаете что использовать сервер вместо калькулятора тоже гуд?
А если так.
Есть сервис.
В нем есть пользователи, хранятся в БД (например в MySQL).
Сервис начинает предоставлять дополнительную услугу — доступ к удаленной директории по FTP. Что лучше держать пользователей в базе и синхронизировать его с файлом, в котором будут хранится пользователи, или добавить пару полей в базу?
Есть сервис.
В нем есть пользователи, хранятся в БД (например в MySQL).
Сервис начинает предоставлять дополнительную услугу — доступ к удаленной директории по FTP. Что лучше держать пользователей в базе и синхронизировать его с файлом, в котором будут хранится пользователи, или добавить пару полей в базу?
за тем, что скорее она уже есть и за тем, что если Вы будете велосипедить подобным образом, то скорее всего для интеграции фтп в некую систему.
где хранить имя, фамилию, статистику использования квоты, список загруженного и т.д.?
где хранить имя, фамилию, статистику использования квоты, список загруженного и т.д.?
встроеный в питон sqlite наверно подошел бы лучше.
честно говоря думал такие статьи остались в начале 2000-х
хотя, как учебный пример наверное хорошо
Да ладно вам, хорошо. Использовать old style классы — моветон, использовать 1 и 0 в качестве булевского выражения — моветон, писать
вместо
бессмысленно и в 4 раза дольше.
Про то, что там в sql запросы передается данные переданные пользователем, без всякого эскейпинга, я уже не говорю — sql injection это сейчас модно в обучающих статьях, как я понимаю.
Зачем такое использовать в качестве учебного примера?
if 'id' in data: return data['id'] else: return None
вместо
return data.get('id')
бессмысленно и в 4 раза дольше.
Про то, что там в sql запросы передается данные переданные пользователем, без всякого эскейпинга, я уже не говорю — sql injection это сейчас модно в обучающих статьях, как я понимаю.
Зачем такое использовать в качестве учебного примера?
обучение не начинают с sql injection и остального, в обучении главное наглядность, а не фунциональность
Делаю смелый вывод что Вы python-программист, и совсем не начального уровня.
Если не сложно скиньте несколько ссылок на полезные статьи (лучше в личку может даже).
Буду очень благодарен. Я не профи я только учусь, поэтому буду рад любому материалу.
Если не сложно скиньте несколько ссылок на полезные статьи (лучше в личку может даже).
Буду очень благодарен. Я не профи я только учусь, поэтому буду рад любому материалу.
Слушайте, это не было наездом на то, что вы чего-то не знаете. Простите если вам так показалось. Мы все вначале пишем плохой код, делаем детские ошибки и прочая — это совершенно нормально. Меня просто удивляют постоянно появляющиеся на главной хабра статьи начинающиеся словами «Я начал изучать python(ruby,java,lisp...) неделю назад и решил написать статью ...».
Что касается статей, то черт его знает. Я, помнится, читал что-то из стандартного набора Learninig P. Dive into P. и Python Cookbook.
Вообще, мне кажется надо просто читать много чужого кода написанного опытными людьми и параллельно официальную питоновскую документацию. Я, когда начинал, копался в коде twisted. Код самих питоновских библиотек можно смотреть. Иногда забавно в код самого питона заглянуть. Парни из pocoo.org пишут очень хорошие либы. Пользуетесь django — читайте джанго, не знаю, правда, что там.
Плюс англоязычные блоги — можно начать с planet python, а потом сами разберетесь кого читать.
Что касается статей, то черт его знает. Я, помнится, читал что-то из стандартного набора Learninig P. Dive into P. и Python Cookbook.
Вообще, мне кажется надо просто читать много чужого кода написанного опытными людьми и параллельно официальную питоновскую документацию. Я, когда начинал, копался в коде twisted. Код самих питоновских библиотек можно смотреть. Иногда забавно в код самого питона заглянуть. Парни из pocoo.org пишут очень хорошие либы. Пользуетесь django — читайте джанго, не знаю, правда, что там.
Плюс англоязычные блоги — можно начать с planet python, а потом сами разберетесь кого читать.
Когда только учитесть, старайтесь хотябы первое время свой код не вывешивать на главной хабра, многие могут скопировать неглядя просто или подумать что так и нужно.
Я знакомство с питоном отсюда начинал:
docs.python.org/tutorial/index.html
Потом уже код простеньких программок из Ubuntu смотрел
Я знакомство с питоном отсюда начинал:
docs.python.org/tutorial/index.html
Потом уже код простеньких программок из Ubuntu смотрел
return data.get('id', None)
:)
:)
Оно и так по умолчанию None.
Class Docstring:
D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None.
Class Docstring:
D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None.
этож бублгум!
в смысле pythonic way — должно быть читабельно и понятно любому, даже не программисту.
Поэтому первые несколько строк были лучше этой одной, но уж если одна, то хотя бы с полным описанием
P.S. PEP8 -> Programming Recommendations
в смысле pythonic way — должно быть читабельно и понятно любому, даже не программисту.
Поэтому первые несколько строк были лучше этой одной, но уж если одна, то хотя бы с полным описанием
P.S. PEP8 -> Programming Recommendations
Я, признаться, не осознал почему написать свой велосипед лучше, чем вызвать наистандартнейшую функцию из core library. Вы другие стандартные функции тоже ручками переписываете для наглядности?
Опять же — перечитал PEP8 -> Programming Recommendations и не нашел ни малейшего упоминания о том, что не рекомендуется использовать значения по умолчанию.
Более того — сделав grep по исходникам питона, я не нашел ни одного случая чтобы там использовали get("...", None) для хешей. Просто вызовов .get(key) зато там навалом. Не все они, конечно, вызываются на dict, но какая-то часть — наверняка.
И вообще мне кажется сомнительной мысль, что разработчики бы реализовывали функцию get, а потом не рекомендовали ее использовать.
Опять же — перечитал PEP8 -> Programming Recommendations и не нашел ни малейшего упоминания о том, что не рекомендуется использовать значения по умолчанию.
Более того — сделав grep по исходникам питона, я не нашел ни одного случая чтобы там использовали get("...", None) для хешей. Просто вызовов .get(key) зато там навалом. Не все они, конечно, вызываются на dict, но какая-то часть — наверняка.
И вообще мне кажется сомнительной мысль, что разработчики бы реализовывали функцию get, а потом не рекомендовали ее использовать.
в каком месте была стандартная фукнция переписана?
А по поводу грепа я не понял… толи Вы им пользоваться не умеете, толи врётё… хотя я думаю, просто другие исходники использовали
Python-2.7.1\Doc\tools\rstlint.py (1 hits)
Line 194: checkerlist = checkers.get(ext, None)
А по поводу грепа я не понял… толи Вы им пользоваться не умеете, толи врётё… хотя я думаю, просто другие исходники использовали
Python-2.7.1\Doc\tools\rstlint.py (1 hits)
Line 194: checkerlist = checkers.get(ext, None)
Ну если я удаляю вызов системной функции, и вставляю свои пять строк которые делают то же самое, то я это называю переписывать.
Вы ведь, к примеру, вызываете any, а не итерируете массив? Используете defaultdict, а не делаете вручную проверки и присвоения?
ух ты. Вы правы, видимо не умею. Пропустил пробел после запятой. Причем если бы я не нашел ничего, я бы заподозрил что-то, но увы, питонисты тоже иногда забывают ставить пробелы. Посыпаю голову пеплом и снимаю этот аргумент.
В любом случае — если бы авторы считали что этот параметр нужно явно указывать, они бы не сделали его опциональным.
Вы ведь, к примеру, вызываете any, а не итерируете массив? Используете defaultdict, а не делаете вручную проверки и присвоения?
ух ты. Вы правы, видимо не умею. Пропустил пробел после запятой. Причем если бы я не нашел ничего, я бы заподозрил что-то, но увы, питонисты тоже иногда забывают ставить пробелы. Посыпаю голову пеплом и снимаю этот аргумент.
В любом случае — если бы авторы считали что этот параметр нужно явно указывать, они бы не сделали его опциональным.
> как учебный пример
Если только пример «как нельзя», потому что код — ппц.
Если только пример «как нельзя», потому что код — ппц.
Каждый второй фтп-сервер поддерживает если не внешние аутентификаторы, то базу юзеров во внешней СУБД.
Велосипед.
Велосипед.
А если нужно повесить триггеры на события по FTP? Например по факту закачки файла или создания директории, выполнять какую-либо функцию. Ни одно стандартное решение не поддерживает это лучше чем путь переопределения методов pyftpd.
Тем временем обычные пользователи пользуются тем же пресловутым ProFTPd, хранят доступы в базе, да еще и квоты заодно
Поддержу предыдущего оратора про proftpd. Годы назад для нее уже сделали модуль для работы с mysql. Сам пакет стабилен, и все у него хорошо. Писать собственный — ну разве что из спортивного интереса
тогда уж лучше vsftpd, имхо
Опыта общения с vsftpd не имел, поэтому пишу о том, о чем знаю. Кроме того, к proftpd есть графическая морда — gproftpd, которая позволяет достаточно удобно добавлять/удалять пользователей. Так что, если не нужно динамическое добавление, то можно использовать эту утилиту и не привязываться в базам. Одним словом, хорошо подходит для домашнего использования
Я в общем то тоже не имел с ним дела, но основное преимущество того же ProFTPd в том, что он перкрасно работает «из-коробки» в Debian. Минимум допиливания и конфиги Apache-style доставляю сильнее. На саом деле, когда серверов в проекте переваливает штук за 20-30 — начинает сказываться «цена» обслуживания. Под цено я имею ввиду не только зарплату сисадмина, а еще и время, которое требуется на настройку всего добра. Цепляние же базы к нему — прекрасно описано, и более того — запросы для работы с табличками вы делаете сами — и соответственно можете привязываться вообще к любой существующей табличке любого другого проекта, что мы и сделали лет этак 6 назад
Поднимать демон на скриптовом языке python — моветон. ftp-сервера с поддержкой mysql и настройкой портов есть уже много-много лет. Поздравляем Вас с разморозкой.
Ооо… А еще говорят что в питоне говнокода нет))
Может я немного преувеличиваю, но уж больно страшно смотрится:
* Зачем обертка над БД? db2 API сам себе прекрасная переносимая обертка (т.е. все реляционные БД в Python должны поддерживать этот интерфейс, см www.python.org/dev/peps/pep-0249/). А так получилась универсальная обертка над универсальной оберткой
* SQL инъекции привет!
* Чтоб получить last insert id существует атрибут .lastrowid курсора (см тот же PEP)
* про if return else return уже заметили
Может я немного преувеличиваю, но уж больно страшно смотрится:
* Зачем обертка над БД? db2 API сам себе прекрасная переносимая обертка (т.е. все реляционные БД в Python должны поддерживать этот интерфейс, см www.python.org/dev/peps/pep-0249/). А так получилась универсальная обертка над универсальной оберткой
* SQL инъекции привет!
sql = "select * from `users` where `username`='%s' and `password`='%s'" % (username,password)
Так в питоне не делают. Используют метод db.execute() с параметрами вроде db.execute(«select * from `users` where `username`='%s' and `password`='%s'», (username,password)) который автоматически экранирование добавляет* Чтоб получить last insert id существует атрибут .lastrowid курсора (см тот же PEP)
* про if return else return уже заметили
Когда изучал питон наткнулся на эту библиотеку… Написал свой авторизатор для mysql тогда.
Могу сразу сказать, что Вас ожидает ошибка mysql server has gone away :).
еще у Вас нет setuid и setgid.
Могу сразу сказать, что Вас ожидает ошибка mysql server has gone away :).
еще у Вас нет setuid и setgid.
Почему меня ожидает ошибка «mysql server has gone away»?
Про setuid и setgid можно подробнее.
Про setuid и setgid можно подробнее.
Прилечу домой скину авторизатор.
Запустите фтпд и авторизуйтесь, после этого оставьте на часов 8 в idle. после этого посыпятся ошибки mysql server has gone away.
Запустите фтпд и авторизуйтесь, после этого оставьте на часов 8 в idle. после этого посыпятся ошибки mysql server has gone away.
Как и обещал, полный листинг, дыр я вроде не находил, т.к. все в escapestring. Пароль сами завернуть можете в md5 надеюсь…
import pwd,os,MySQLdb
class MysqlAuthorizer(ftpserver.DummyAuthorizer):
PROCESS_UID = os.getuid()
PROCESS_GID = os.getgid()
ml = None
def __init__(self, ml={'user':'','passwd':'','db':'','host':''}):
if ml['host'].startswith("/"):
ml['us'] = ml['host']
ml['host'] = 'localhost'
self.ml = ml
self.connect()
return
def connect(self):
ml = self.ml
try:
db=MySQLdb.connect(host=ml['host'],user=ml['user'],passwd=ml['passwd'],db=ml['db'],unix_socket=ml['us'])
self.c = db.cursor()
except:
return
def add_user():
return
def add_anonymous():
return
def remove_user():
return
def impersonate_user(self, username, password):
try:
self.c.execute(«SELECT uid FROM users WHERE user = %s AND passwd = %s LIMIT 1», (username,password))
except:
self.connect()
self.c.execute(«SELECT uid FROM users WHERE user = %s AND passwd = %s LIMIT 1», (username,password))
re = self.c.fetchone()
t = pwd.getpwuid(re[0])
os.setegid(t.pw_gid)
os.seteuid(t.pw_uid)
def terminate_impersonation(self):
os.setegid(self.PROCESS_GID)
os.seteuid(self.PROCESS_UID)
def validate_authentication(self, username, password):
try:
self.c.execute(«SELECT id FROM users WHERE user = %s AND passwd = %s LIMIT 1», (username,password))
except:
self.connect()
self.c.execute(«SELECT id FROM users WHERE user = %s AND passwd = %s LIMIT 1», (username,password))
return self.c.rowcount
def has_user(self, username):
try:
self.c.execute(«SELECT id FROM users WHERE user = %s LIMIT 1», (username,))
except:
self.connect()
self.c.execute(«SELECT id FROM users WHERE user = %s LIMIT 1», (username,))
return self.c.rowcount
def has_perm(self, username, perm, path=None):
try:
self.c.execute(«SELECT id FROM users WHERE user = %s AND perm LIKE %s LIMIT 1», (username,''.join(['%',perm,'%'])))
except:
self.connect()
self.c.execute(«SELECT id FROM users WHERE user = %s AND perm LIKE %s LIMIT 1», (username,''.join(['%',perm,'%'])))
return self.c.rowcount
def get_perms(self, username):
try:
self.c.execute(«SELECT perm FROM users WHERE user = %s LIMIT 1», (username,))
except:
self.connect()
self.c.execute(«SELECT perm FROM users WHERE user = %s LIMIT 1», (username,))
re = self.c.fetchone()
return re[0].strip(",")
def get_home_dir(self, username):
try:
self.c.execute(«SELECT homedir FROM users WHERE user = %s LIMIT 1», (username,))
except:
self.connect()
self.c.execute(«SELECT homedir FROM users WHERE user = %s LIMIT 1», (username,))
re = self.c.fetchone()
return re[0]
def get_msg_login(self, username):
return «Hallo!»
def get_msg_quit(self, username):
return «Bye bye...»
import pwd,os,MySQLdb
class MysqlAuthorizer(ftpserver.DummyAuthorizer):
PROCESS_UID = os.getuid()
PROCESS_GID = os.getgid()
ml = None
def __init__(self, ml={'user':'','passwd':'','db':'','host':''}):
if ml['host'].startswith("/"):
ml['us'] = ml['host']
ml['host'] = 'localhost'
self.ml = ml
self.connect()
return
def connect(self):
ml = self.ml
try:
db=MySQLdb.connect(host=ml['host'],user=ml['user'],passwd=ml['passwd'],db=ml['db'],unix_socket=ml['us'])
self.c = db.cursor()
except:
return
def add_user():
return
def add_anonymous():
return
def remove_user():
return
def impersonate_user(self, username, password):
try:
self.c.execute(«SELECT uid FROM users WHERE user = %s AND passwd = %s LIMIT 1», (username,password))
except:
self.connect()
self.c.execute(«SELECT uid FROM users WHERE user = %s AND passwd = %s LIMIT 1», (username,password))
re = self.c.fetchone()
t = pwd.getpwuid(re[0])
os.setegid(t.pw_gid)
os.seteuid(t.pw_uid)
def terminate_impersonation(self):
os.setegid(self.PROCESS_GID)
os.seteuid(self.PROCESS_UID)
def validate_authentication(self, username, password):
try:
self.c.execute(«SELECT id FROM users WHERE user = %s AND passwd = %s LIMIT 1», (username,password))
except:
self.connect()
self.c.execute(«SELECT id FROM users WHERE user = %s AND passwd = %s LIMIT 1», (username,password))
return self.c.rowcount
def has_user(self, username):
try:
self.c.execute(«SELECT id FROM users WHERE user = %s LIMIT 1», (username,))
except:
self.connect()
self.c.execute(«SELECT id FROM users WHERE user = %s LIMIT 1», (username,))
return self.c.rowcount
def has_perm(self, username, perm, path=None):
try:
self.c.execute(«SELECT id FROM users WHERE user = %s AND perm LIKE %s LIMIT 1», (username,''.join(['%',perm,'%'])))
except:
self.connect()
self.c.execute(«SELECT id FROM users WHERE user = %s AND perm LIKE %s LIMIT 1», (username,''.join(['%',perm,'%'])))
return self.c.rowcount
def get_perms(self, username):
try:
self.c.execute(«SELECT perm FROM users WHERE user = %s LIMIT 1», (username,))
except:
self.connect()
self.c.execute(«SELECT perm FROM users WHERE user = %s LIMIT 1», (username,))
re = self.c.fetchone()
return re[0].strip(",")
def get_home_dir(self, username):
try:
self.c.execute(«SELECT homedir FROM users WHERE user = %s LIMIT 1», (username,))
except:
self.connect()
self.c.execute(«SELECT homedir FROM users WHERE user = %s LIMIT 1», (username,))
re = self.c.fetchone()
return re[0]
def get_msg_login(self, username):
return «Hallo!»
def get_msg_quit(self, username):
return «Bye bye...»
Sign up to leave a comment.
FTP сервер с авторизацией через базу данных