Pull to refresh

Comments 56

Во-во, pureftpd — наше все ;-)
Базу можно подобрать под себя любую.
Why not?
Я вот не вижу каких-то однозначных причин не использовать mysql для этих целей.
Другое дело пароли в открытом виде, но и для этого могут быть причины.
а кто мешает хранить их в MD5?
Можно сказать, что это прототип.
да конечно не что не мешает.
это я написал в тему, что уж если хочется придраться, то лучше к этому чем к mysql — тут хоть какую-то причину придумать можно
Согласен. В моем понимание это называется конструктивная критика :)
Иногда нужно интегрировать FTP с существующей базой пользователей на Mysql или другой. В этом случае проще использовать СУБД напрямую чем через md5/sqllite
А кто сказал что mySQL не подходит. Гвозди тоже можно микроскопом забивать. А какие у mySQL преимущества перед другими бд для хранения паролей?
зависит от условий
пускай юзеров 100 000 и они пытаются поддерживать фтп соединение по фиговым каналам. лучше в plain text хранить?
а если учесть что на сервере скорее всего уже стоит mysql, то чем лучше тот sqlite или plain text?
в каком месте myisam на микроскоп для гвоздей похож?
Чем mySQL лучше других БД для хранения паролей? И какая разница сколько юзеров?
MySQL — реляционная СУБД. Зачем к примеру вам для хранения паролей все плюшки mySQL? Это и есть забивание гвоздей микроскопом. Или вы считаете что использовать сервер вместо калькулятора тоже гуд?
А если так.
Есть сервис.
В нем есть пользователи, хранятся в БД (например в MySQL).
Сервис начинает предоставлять дополнительную услугу — доступ к удаленной директории по FTP. Что лучше держать пользователей в базе и синхронизировать его с файлом, в котором будут хранится пользователи, или добавить пару полей в базу?
А причем тут файлы? Я не могу понять зачем Вам для хранения паролей mySQL?
Предложите вариант, где хранить пароли пользователей, если все остальные параметры хранятся в БД?
UFO just landed and posted this here
за тем, что скорее она уже есть и за тем, что если Вы будете велосипедить подобным образом, то скорее всего для интеграции фтп в некую систему.
где хранить имя, фамилию, статистику использования квоты, список загруженного и т.д.?
1) С каких это пор mySQL входит в состав хотя бы одной ОС?
2) В базе данных.
не надо читать мои комменты между строк — читайте всё.
1. я писал что «скорее всего» она там есть. и не писал что она входит в состав ОС
2. mysql — тоже база данных. класс? :)
встроеный в питон sqlite наверно подошел бы лучше.
это как вариант хранения данных.
честно говоря думал такие статьи остались в начале 2000-х
Да ладно вам, хорошо. Использовать old style классы — моветон, использовать 1 и 0 в качестве булевского выражения — моветон, писать
        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, а потом сами разберетесь кого читать.
Ни в коем случае не считал это наездом.
Мой комментарий был скорее просьбой.
Спасибо за советы.
Я постараюсь ими воспользоваться и в следующий раз предлагать более качественный код.
Когда только учитесть, старайтесь хотябы первое время свой код не вывешивать на главной хабра, многие могут скопировать неглядя просто или подумать что так и нужно.

Я знакомство с питоном отсюда начинал:
docs.python.org/tutorial/index.html

Потом уже код простеньких программок из Ubuntu смотрел
Оно и так по умолчанию 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
Я, признаться, не осознал почему написать свой велосипед лучше, чем вызвать наистандартнейшую функцию из core library. Вы другие стандартные функции тоже ручками переписываете для наглядности?

Опять же — перечитал 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)
Ну если я удаляю вызов системной функции, и вставляю свои пять строк которые делают то же самое, то я это называю переписывать.

Вы ведь, к примеру, вызываете any, а не итерируете массив? Используете defaultdict, а не делаете вручную проверки и присвоения?

ух ты. Вы правы, видимо не умею. Пропустил пробел после запятой. Причем если бы я не нашел ничего, я бы заподозрил что-то, но увы, питонисты тоже иногда забывают ставить пробелы. Посыпаю голову пеплом и снимаю этот аргумент.

В любом случае — если бы авторы считали что этот параметр нужно явно указывать, они бы не сделали его опциональным.
да конечно можно не указывать. на питоне можно писать по разному — чего только стоят люмбда функции и создание списков на лету.
НО если мы говорим о качестве кода, то для python есть PEP.
а набирает питон популярность как раз благодаря авторам, которые дают возможность писать как душе угодно
Каждый второй фтп-сервер поддерживает если не внешние аутентификаторы, то базу юзеров во внешней СУБД.

Велосипед.
А если нужно повесить триггеры на события по FTP? Например по факту закачки файла или создания директории, выполнять какую-либо функцию. Ни одно стандартное решение не поддерживает это лучше чем путь переопределения методов pyftpd.
FTP работает с файловой системой. Для слежки за событиями файловой системы есть inotify. И вообще, это дополнительное условие, о котором angry_elf не знал при написании своего комментария. :P
Тем временем обычные пользователи пользуются тем же пресловутым ProFTPd, хранят доступы в базе, да еще и квоты заодно
Поддержу предыдущего оратора про proftpd. Годы назад для нее уже сделали модуль для работы с mysql. Сам пакет стабилен, и все у него хорошо. Писать собственный — ну разве что из спортивного интереса
Опыта общения с vsftpd не имел, поэтому пишу о том, о чем знаю. Кроме того, к proftpd есть графическая морда — gproftpd, которая позволяет достаточно удобно добавлять/удалять пользователей. Так что, если не нужно динамическое добавление, то можно использовать эту утилиту и не привязываться в базам. Одним словом, хорошо подходит для домашнего использования
Я в общем то тоже не имел с ним дела, но основное преимущество того же ProFTPd в том, что он перкрасно работает «из-коробки» в Debian. Минимум допиливания и конфиги Apache-style доставляю сильнее. На саом деле, когда серверов в проекте переваливает штук за 20-30 — начинает сказываться «цена» обслуживания. Под цено я имею ввиду не только зарплату сисадмина, а еще и время, которое требуется на настройку всего добра. Цепляние же базы к нему — прекрасно описано, и более того — запросы для работы с табличками вы делаете сами — и соответственно можете привязываться вообще к любой существующей табличке любого другого проекта, что мы и сделали лет этак 6 назад
vsftpd тоже работает прекрасно из коробки. Авторизацию можно прикрутить через pam или встроенными средствами vsftpd. Единственное преимущество proftpd перед vsftpd — это gui морда, имхо. Конфиги — дело привычки.
Поднимать демон на скриптовом языке python — моветон. ftp-сервера с поддержкой mysql и настройкой портов есть уже много-много лет. Поздравляем Вас с разморозкой.
Ооо… А еще говорят что в питоне говнокода нет))

Может я немного преувеличиваю, но уж больно страшно смотрится:
* Зачем обертка над БД? 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 можно подробнее.
Прилечу домой скину авторизатор.
Запустите фтпд и авторизуйтесь, после этого оставьте на часов 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...»
Sign up to leave a comment.

Articles