def on_user_create(new_user): print "on_user_create" permissions = new_user.merged_permissions() # If the user has "FTP client" rights then create an FTP user if "ftp_client" in permissions["proftpd"]: username, password = new_user.username, new_user.password proftpd = Proftpd(new_user) # We don't like spaces in directory names, so replace them with underscores homedir = os.path.join(proftpd.config["DefaultRoot"][0], \ username.replace(" ", "_")) # Create FTP user ftp_user = Users.objects.create(username=username, password=crypt.crypt(password, password), homedir=homedir) # Creating a home directory if not (os.path.exists(homedir) and os.path.isdir(homedir)): os.mkdir(homedir) # Changing the owner try: os.chown(homedir, PROFTPD_UID, PROFTPD_GID) except OSError, (errno, sterror): log(3, "proftpd_app - event:on_user_create", "OS error(%s): %s" % (errno, sterror)) # Creating user groups for group in new_user.groups.all(): Groups.objects.create(groupname=group.name, username=username) proftpd.update_config()
def on_user_change(user, data): username = user.username new_password = data.get('password', None) ftp_user, created = Users.objects.get_or_create(username=username) proftpd = Proftpd() if created: ftp_user.homedir = os.path.join(proftpd.config["DefaultRoot"][0], \ username.replace(" ", "_")) try: os.mkdir(ftp_user.homedir) os.chown(ftp_user.homedir, PROFTPD_UID, PROFTPD_GID) # Changing owner except OSError: log(5, "proftpd_app - event:on_user_change", "Failed to create directory or alter its owner") # Changing users's password if new_password: ftp_user.password = crypt.crypt(new_password, new_password) ftp_user.save() # Updating directory permissions if "ftp_client" in user.merged_permissions()["proftpd"]: proftpd.update_config() # Recreating groups ftp_groups = Groups.objects.filter(username=username) ftp_groups.delete() for group in user.groups.all(): Groups.objects.create(groupname=group.name, username=username) return 1
def max_permissions(self, map=None): if not map: map = Permission.map if isinstance(map, dict): rslt = {} for m in map: rslt[m] = self.max_permissions(map[m]) return rslt elif hasattr(map, "cls") and map.cls == "form": if isinstance(map.value, dict): first_value = map.value[map.value.keys()[0]] if first_value.type == "radio": best_value = first_value for key in map.value: if best_value < map.value[key]: best_value = map.value[key] return {best_value.name: self.max_permissions(best_value)} else: return self.max_permissions(map.value) else: return "" elif isinstance(map, (basestring, unicode)): return map log(7, "admin_app - Permission class", "max_permissions: Unrecogniseable type") return None
def radio(*args): rate = 0 radios = S() args = list(args) while len(args): radio_title, radio_value = args.pop(0), args.pop(0) if isinstance(radio_value, (basestring, unicode)): radios[radio_value] = _Radio(radio_value, radio_title, radio_value, rate) elif isinstance(radio_value, dict): value_key = radio_value.keys()[0] if not isinstance(radio_value[value_key], (tuple, list)): radio_value[value_key] = (radio_value[value_key],) tmp_radios = S() for radio in radio_value[value_key]: if isinstance(radio, dict): key = radio.keys()[0] tmp_radios.update(radio) else: log(5, "admin_app - radio function", "Type mismatch.") radios[value_key] = _Radio(value_key, radio_title, tmp_radios, rate) else: log(5, "admin_app - radio function", "Unknown radio_value type.") rate += 1 return radios
def __dissect(self, perm1, perm2, map=None): if isinstance(perm1, dict) and isinstance(perm2, dict): perm = {} for p in perm1: if not p in perm2: perm[p] = deepcopy(perm1[p]) else: pp = self.__dissect(perm1[p], perm2[p], map[p]) if pp: perm[p] = pp return perm elif perm1 and not perm2: return perm1 else: if isinstance(perm1, (unicode, basestring)) and isinstance(perm2, dict): perm2_str = perm2.keys()[0] perm1_str = perm1 elif isinstance(perm1, dict) and isinstance(perm2, (unicode, basestring)): perm2_str = perm2 perm1_str = perm1.keys()[0] elif isinstance(perm1, (unicode, basestring)) and isinstance(perm2, (unicode, basestring)): perm2_str = perm2 perm1_str = perm1 else: log(7, "admin_app - Permission class", "__dissect: Comparison type mismatch!") return None if perm1_str and perm2_str: if map[perm1_str] > map[perm2_str]: return perm1 else: return "" return None
def update_config(self): self.config.update(Groups.objects.all().distinct(), Users.objects.all()) if self.config.save(): self.reconfig() return 1 else: log(8, "ProftpdConfig - config update", "Failed to update config") return 0
def __render(self, map, min_permission, max_permission, default): html = "" for p in max_permission: if p in map: if map[p].type == "radio": """ We also have to fetch the minimum permission to disable forms which reprensent even lower permissions. In order to do this, if min_permission contains a non-null dictionary than get its first value. """ min_perm = min_permission if min_perm: for map_key in min_permission: min_perm = min_permission[map_key] break """ As there should be a default value in a radio button set in any case, check the default and if it's empty set the lowest possible (not disabled) permission from the map as the default """ if not default: for map_key in map: if map[map_key] >= min_perm: default[map_key] = map[map_key] break """ Now, go through the map and disable all permissions which are lower than the min_permission and hide all which are higher than max_permission. """ for map_key in map: if map[map_key] <= max_permission[p]: radio = map[map_key].html(bool(map[map_key] < min_perm), \ bool(map[map_key].name in default)) if map[map_key].stub: html += "<li>%s</li>" % radio else: inner = self.__render(map[map_key], min_permission.get(map_key, {}), self.to_map(self.max_permissions(map[map_key]), map[map_key]), default.get(map_key, {})) html += '<li>%s<ul class="form">%s</ul></li>' % (radio, inner) else: break elif map[p].type in ("title", "checkbox"): min_perm = min_permission.get(p, {}) def_perm = default.get(p, {}) if not map[p].stub: html_form = map[p].html(bool(min_perm), bool(def_perm)) a = self.__render(map[p], min_perm, max_permission[p], def_perm) html += '<li>%s<ul class="form">%s</ul></li>' % (html_form, a) else: html += "<li>%s</li>" % map[p].html(bool(min_permission.get(p, {})), bool(default.get(p, {}))) else: log(7, "admin_app - Permission class", "__render: Unknown type %s" % map[p].type) return html
def update(self): serial = self.config[self.zone_name]['SOA']['params']['serial'] self.config[self.zone_name]['SOA']['params']['serial'] = str(int(serial)+1) if self.save(): render_to_task("rndc reload %s" % self.zone_name) return 1 else: log(8, "ZoneConfig - serial update", "Failed to update serial for a zone %s" % self.zone_name) return 0
def gen_map(): result = S() apps = map(lambda x: x.split(".")[1], filter(lambda x: x.split(".")[0]=="wenix", INSTALLED_APPS)) for p in apps: try: perm = __import__("wenix.%s.permissions" % p, globals(), locals(), ['MAP']) except ImportError: log(3, "<Permission.gen_map>", "Ignoring permissions for '%s'" % p) else: result.update(perm.MAP) return result
def on_user_login(request, user): ip_address = request.META["REMOTE_ADDR"] user_agent = uainfo(request.META["HTTP_USER_AGENT"]) try: name = "%s %s" % (user_agent["browser"]["name"], user_agent["browser"]["version"]) distrib = "%s %s" % (user_agent["dist"]["name"], user_agent["dist"]["version"]) obj, created = UserAgent.objects.get_or_create(codename=user_agent["browser"]["name"], name=name, ip_address=ip_address, platform=user_agent["os"]["name"], defaults={"distrib":distrib,"count": 0}) obj.count += 1 obj.save() except: log(5,"misc.middleware.Counter", "Error occured while parsing '%s'" % user_agent)
def to_dictionary(self, mapped_perm): d = {} for m in mapped_perm: if isinstance(mapped_perm[m], dict): d[m] = self.to_dictionary(mapped_perm[m]) elif hasattr(mapped_perm[m], "cls") and mapped_perm[m].cls == "form": if isinstance(mapped_perm[m].value, dict): d[m] = self.to_dictionary(mapped_perm[m].value) elif mapped_perm[m].type == "radio": return mapped_perm[m].name else: d[m] = "" else: log(7, "admin_app - Permission class", "to_dictionary: unrecognizeable type: '%s'" % mapped_perm[m]) return d
def __cmp(self, perm1, perm2, map): in_form = bool(hasattr(perm1, "cls") and hasattr(perm2, "cls")) stub = bool(in_form and perm1.stub and perm2.stub) if isinstance(perm1, dict) and isinstance(perm2, dict): for p in perm2: if not p in perm1: return -1 else: cmp = self.__cmp(perm1[p], perm2[p], map[p]) if cmp: return cmp for p in perm1: if not p in perm2: return 1 else: if isinstance(perm1, (unicode, basestring)) and isinstance(perm2, dict): perm2_str = perm2.keys()[0] perm1_str = perm1 elif isinstance(perm1, dict) and isinstance(perm2, (unicode, basestring)): perm2_str = perm2 perm1_str = perm1.keys()[0] elif isinstance(perm1, (unicode, basestring)) and isinstance(perm2, (unicode, basestring)): perm2_str = perm2 perm1_str = perm1 else: # Type mismatch log(7, "admin_app - Permission class", "__cmp: comparison type mismatch!") return None if perm1_str and perm2_str: if map[perm2_str] > map[perm1_str]: return -1 elif map[perm2_str] == map[perm1_str]: return 0 else: return 1 return 0
def __merge(self, perm1, perm2, map): if isinstance(perm1, dict) and isinstance(perm2, dict): for p in perm2: if not p in perm1: perm1[p] = deepcopy(perm2[p]) else: perm1[p] = self.__merge(perm1[p], perm2[p], map[p]) return perm1 elif perm2 and not perm1: return perm1 else: if isinstance(perm1, (unicode, basestring)) and isinstance(perm2, dict): perm2_str = perm2.keys()[0] perm1_str = perm1 elif isinstance(perm1, dict) and isinstance(perm2, (unicode, basestring)): perm2_str = perm2 perm1_str = perm1.keys()[0] elif isinstance(perm1, (unicode, basestring)) and isinstance(perm2, (unicode, basestring)): perm2_str = perm2 perm1_str = perm1 else: # Type mismatch log(7, "admin_app - Permission class", "__merge: Comparison type mismatch!") return None if perm1_str and perm2_str: if map[perm2_str] > map[perm1_str]: return perm2_str else: return perm1_str elif perm2_str and not perm1_str: return perm2 else: return perm1 # Type mismatch return None
def checkbox(*args): checkboxes = S() args = list(args) while len(args): title, value = args.pop(0), args.pop(0) if isinstance(value, dict): value_key = value.keys()[0] if not isinstance(value[value_key], (tuple, list)): value[value_key] = (value[value_key],) tmp_chkboxes = S() for d in value[value_key]: if isinstance(d, dict): tmp_chkboxes.update(d) else: log(5, "admin_app - checkbox function", "Type mismatch.") checkboxes[value_key] = _Checkbox(value_key, title, tmp_chkboxes) elif isinstance(value, (basestring, unicode)): checkboxes[value] = _Checkbox(value, title, value) else: log(5, "admin_app - checkbox function", "Unrecognised value type") return checkboxes
def on_user_delete(user, victim): mode = user.merged_permissions()['accounts']['actions']['mode'] username = victim.username groups = Groups.objects.filter(username=username) groups.delete() try: ftp_user = Users.objects.get(username=username) except: log(1, "proftpd_app - event:on_user_delete", "No user with username '%s' has been found" % username) return 1 homedir = ftp_user.homedir # Gonna make changes to the config proftpd = Proftpd(user) config = proftpd.config # Deleting the user from permission instances in the config permissions = victim.merged_permissions() if "ftp_client" in permissions["proftpd"]: users = Users.objects.exclude(username='******') homedirs = [] [homedirs.append(user.homedir) for user in users] config.remove(["<Directory>", homedirs, "<Limit>", "*"], "AllowUser", [username]) # Deleting <Directory> instance from config path = proftpd.path() for p in path.ftp_dir_generator("/"+username, childs_only=True): config.drop(["<Directory>"], [p]) if p in FTP_DB: del FTP_DB[FTP_DB[p]] # Deleting the user's instances from DB permissions for dir in FTP_DB: dir_perm = dict(FTP_DB[dir]) if "user" in dir_perm and username in dir_perm["user"]: del dir_perm["user"][username] FTP_DB[dir] = dir_perm FTP_DB.save() # Deleting the directory itself try: shutil.rmtree(homedir) except: log(3, "proftpd_app - event:on_user_delete", "Failed to delete user's directory") if ftp_user: ftp_user.delete() # Reconfiguring... if not proftpd.update_config(): log(3, "proftpd_app - event:on_user_delete", "Failed to delete 'Directory' instance from the configuration file") return 1
def __process(self, name, apps, *args): rslts = {} for app in apps: try: APP = __import__("wenix.%s.event" % app, globals(), locals(), [name]) except ImportError, e: log(1, "custom - user:__process", "Event load failure (%s): %s" % (app, e)) else: try: sub = getattr(APP, name) except: log(0, "custom - group:__process", "Application '%s' has no event '%s'" % (app, name)) else: rslt = sub(*args) if not rslt: log(6, "custom - group:__process", "Unsuccessful result returned from '%s' application" % app) else: rslts[app] = rslt
def title(*args): titles = S() args = list(args) while len(args): title_key, title_value = args.pop(0), args.pop(0) if isinstance(title_value, dict): if not len(title_value) == 1: log(3, "admin_app - title function", "Dictionary length is more than one") break child_key = title_value.keys()[0] if isinstance(title_value[child_key], dict): child_value = title_value[child_key] else: log(3, "admin_app - title function", "Unknown title type") titles[child_key] = _Title(child_key, title_key, child_value) else: log(5, "admin_app - title function", "Unknown title's value type") break return titles
def delete(request, perm): user = request.user id = request.GET.get("id", None) object = request.GET.get("object", None) confirm_request = request.GET.get("cfm_req", None) mode = user.merged_permissions()['accounts']['actions']['mode'] if not (id and object): log(5, "accounts_app - account delete", "Void request") return HttpResponseBadRequest() if not object in ("user", "group"): log(5, "accounts_app - account delete", "Unrecognised object type '%s'" % object) return HttpResponseBadRequest() if object == "user": # User deletion victim = WenixUser.objects.get(pk=id) if victim.is_superuser: log(5, "accounts_app - account delete", "An attempt to delete a superuser by '%s'" % request.user.username) return HttpResponse(json.dumps({"ok": 0, "error": _("Superuser cannot be deleted")}), mimetype="application/json") if victim == user: log(5, "accounts_app - account delete", "An attempt of self-deletion by '%s'" % request.user.username) return HttpResponse(json.dumps({"ok": 0, "error": _("You cannot delete yourself")}), mimetype="application/json") # We are just going to ask for confirmation # qstn - an array with questions and some information about what is going to be deleted # qstn is then concatenated into one string if confirm_request: qstn = [] info = WenixUser.objects.info(user, victim).values() if info: info[0] = " - %s" % info[0] qstn.append(" - \n".join(info)) qstn.append(_('Are you sure you want to delete the user %(username)s? All user-related information, including files and statistics, will be lost.') % {'username': victim.username}) return HttpResponse(json.dumps({"confirm": "\n".join(qstn)}), mimetype="application/json") WenixUser.objects.on_delete(user, victim) #cache.delete(CACHE_KEY_USERPERM % victim.username) if mode == 'group': for group in victim.groups.all(): if group in user.groups: victim.groups.remove(group) if victim.groups.count() == 0: victim.delete() elif mode == 'global': victim.delete() else: # object == "group": # Group deletion if mode != "global": log(5, "accounts_app - account delete", "An attempt to delete a group without global piviliges by '%s'" % user.username) return HttpResponseForbidden() # In a global mode # Fetching all users in the group group = WenixGroup.objects.get(pk=id) group_users = WenixUser.objects.filter(groups__name=group.name) # We are just going to ask for confirmation if confirm_request: # Finding out users to be deleted qstn = [] usernames = [] for u in group_users: if u.groups.count() == 1: usernames.append(u.username) if usernames: users = ", ".join(usernames) qstn.append(_("These users are going to be deleted: %(users)s. ") % {'users': users}) info = WenixGroup.objects.info(user, group).values() if info: info[0] = " - %s" % info[0] qstn.append("\n - ".join(info)) qstn.append(_("Are you sure you want to delete the group %(groupname)s?") % {'groupname': group.name}) return HttpResponse(json.dumps({"confirm": "\n".join(qstn)}), mimetype="application/json") # Informing external modules WenixGroup.objects.on_delete(user, group) # Deleting the group for u in group_users: if u.groups.count() == 1: WenixUser.objects.on_delete(user, u) u.delete() else: u.groups.remove(group) #cache.delete(CACHE_KEY_UGRPERM % u.username) #cache.delete(CACHE_KEY_USERPERM % u.username) group.delete() return HttpResponse(json.dumps({"ok": 1}), mimetype="application/json")
def manage(request, mode, action): data_str = request.POST.get("data", None) formset_id = request.COOKIES.get("formset_id", None) instance_id = request.POST.get("id", request.GET.get("id", None)) data = None # If in the "edit" mode, account_obj contains either a user or a group object # Otherwise the object is None account_obj = None """ If data is send, write this data in cache and follow the following steps accordingly. Otherwise, if it's a step back return the cached data. In any other case it should be the first request in a formset, so return an empty form. """ if data_str: # The user is submitting the form. Trying to deserialize data first. try: data = json.loads(data_str) except: # Damn... returng a bad request error log(6, "accounts_app - account add", "Failed to serialize data string: %s" % data_str) return HttpResponseBadRequest() # Let's dig out the previously recorded data from the cache. formset = cache.get(formset_id) # If the request uses POST method, apperently the user is submiting the form if request.method == "POST": if formset: step = formset["step"] object = formset["object"] # Fetching an object from the DB if instance_id and action == "edit": if object == "user": class_obj = WenixUser else: class_obj = WenixGroup account_obj = class_obj.objects.get(pk=instance_id) if data: # Get the form and check wether the submitted data valid or not. form = get_form(object.title(), action, step)(data) if not form.is_valid(): print data print form return HttpResponse(json.dumps({"ok": 0,"errors": get_errors(form, data)}), mimetype="application/json") # Update formset. All data in the following lines could be reached # only with the formset. formset["data"].update(data) """ If it's the last step in a formset we don't need to return the next step, but rather we return the result of the user/group creation. """ if object == "user" and step == 3: u_perm_obj = Permission(formset["data"]["permissions"]) perm_obj = Permission(request.user.merged_permissions()) groups = WenixGroup.objects.in_bulk(formset["data"]["groups"]).values() g_perm_obj = Permission() for group in groups: g_perm_obj.merge(group.permissions) if u_perm_obj >= g_perm_obj and u_perm_obj <= perm_obj: """ Priviliges check has passed. We have nothing to do but to create or change the user. We don't want redundancy, therefore the common attributes will be fetched here. """ # User permissions first permissions = u_perm_obj.dissect(g_perm_obj.permissions) if action == "add": new_user = WenixUser.objects.create(username=formset["data"]["username"]) # Saving general information about the user for key in ("first_name", "last_name", "email", "permissions"): setattr(new_user, key, formset["data"][key]) # Changing the user's membership new_user.groups = groups # We need to store a clean user password in order for # other modules to be aware of it new_user.password = formset["data"]["password"] # Invoking a method to notify all modules about the new user WenixUser.objects.on_create(new_user) # Setting crypted password and saving the user new_user.set_password(formset["data"]['password']) new_user.save() message = _("A new user '%(username)s' has been created") % {"username": new_user.username} else: # action == "edit" account_obj.save() # Saving general information about the user for key in ("first_name", "last_name", "email", "permissions"): setattr(account_obj, key, formset["data"][key]) # Resetting the user's password if needed if formset["data"]['password']: account_obj.set_password(formset["data"]['password']) # Changing the user's membership account_obj.groups = groups account_obj.save() # Invoking a method to notify all modules about the change WenixUser.objects.on_edit(account_obj, formset["data"]) message = _("The user '%(username)s' has been changed") % {"username": account_obj.username} response = HttpResponse(json.dumps({"ok": 1,"message": message})) response.delete_cookie("formset_id") return response else: """ It turns out as if the user created another user with higher priviliges. That breaks the rules, therefore access should be denied. """ log(5, "accounts_app - account add", "Permission denied for user '%s' creating another user" % request.user.username) return HttpResponse(json.dumps({"ok": 1, "message": _("Access denied")})) elif object == "group" and step == 2: g_perm_obj = Permission(formset["data"]["permissions"]) perm_obj = Permission(request.user.merged_permissions()) if g_perm_obj <= perm_obj: # Fetching users to be included in the group users = WenixUser.objects.in_bulk(formset["data"]["users"] or []).values() """ Priviliges check has passed. We have nothing to do but to create or change the group. """ if action == "add": # We are going to create a new group. group = WenixGroup.objects.create(name=formset["data"]["name"], permissions=g_perm_obj.permissions) # The new members of the group should have their priviliges updated [user.groups.add(group) for user in users] WenixGroup.objects.on_create(group) message = _("A new group '%(name)s' has been created") % {"name": formset["data"]["name"]} else: # action == "edit" # We are going to change a group. group = account_obj # Reseting users's permissions so they can form again # At the same time if a user was in the MultipleChoice # field remove his membership from the group choice_ids = dict(id_and_name_to_dict(request.user, mode, "user")).keys() old_group_users = WenixUser.objects.filter(groups__name=group.name) for u in old_group_users: #cache.delete(CACHE_KEY_UGRPERM % u.username) #cache.delete(CACHE_KEY_USERPERM % u.username) if str(u.id) in choice_ids: u.groups.remove(group) # Contructing a new dictionary with old_dat to pass with "on_edit" method old_data = {"permissions": group.permissions, "users": old_group_users} group.permissions = g_perm_obj.permissions group.save() # We're going to add users to the group for user in users: user.groups.add(group) #if not user in old_group_users: # cache.delete(CACHE_KEY_UGRPERM % user.username) # cache.delete(CACHE_KEY_USERPERM % user.username) # On edit method has three arguments: user, object_being_changed and new_data WenixGroup.objects.on_edit(request.user, group, old_data) message = _("The priviliges for the group '%(name)s' have been saved") % {"name": group.name} response = HttpResponse(json.dumps({"ok": 1,"message": message})) response.delete_cookie("formset_id") return response else: """ It turns out as if the user created another group with higher priviliges. That breaks the rules, therefore access should be denied. """ log(6, "accounts_app - account add", "Permission denied for user '%s' creating another group" % request.user.username) return HttpResponse(json.dumps({"ok": 1,"message": _("Access denied")})) formset["step"] += 1 else: if formset["step"] > 1: formset["step"] -= 1 else: formset["step"] = 1 step = formset["step"] form = get_form(object.title(), action, step) # Generating the next form according to the step if object == "user": if step == 1: new_form = form(initial=formset["data"]) elif step == 2: """ We need to initialize group list here. At the same time we can't list groups the user is not a memeber of if she's in the "group" mode. That's why we use "id_and_name_to_dict" function to generate the list. """ new_form = form(initial=formset['data']) new_form["groups"].field.choices = id_and_name_to_dict(request.user, mode, "group") elif step == 3: # Generating permissions groups = WenixGroup.objects.in_bulk(data["groups"]) perm_obj = Permission(request.user.merged_permissions()) g_perm_obj = Permission() for g in groups: g_perm_obj.merge(groups[g].permissions) if action == "add": new_form = {"permissions": perm_obj.render(g_perm_obj.permissions)} else: # action == "edit" u_perm_obj = Permission(account_obj.permissions) u_perm_obj.merge(g_perm_obj.permissions) new_form = {"permissions": perm_obj.render(g_perm_obj.permissions, u_perm_obj.permissions)} else: # Unrecognised step log(6, "accounts_app - account add", "Unknown step: %s" % step) return HttpResponseBadRequest() elif object == "group": if step == 1: new_form = form(initial=formset["data"]) new_form["users"].field.choices = id_and_name_to_dict(request.user, mode, "user") elif step == 2: # Generating permissions perm_obj = Permission(request.user.merged_permissions()) if action == "add": new_form = {"permissions": perm_obj.render()} else: # action == "edit" g_perm_obj = Permission(WenixGroup.objects.get(pk=instance_id).permissions) new_form = {"permissions": perm_obj.render({}, g_perm_obj.permissions)} else: # Unrecognised step log(6, "accounts_app - account add", "Unknown step: %s" % step) return HttpResponseBadRequest() template = get_template(TEMPLATE_FORM_PATH % object) cache.set(formset_id, formset) context = Context({"form": new_form, "step": formset["step"], "action": action, "object": account_obj}) return HttpResponse(json.dumps({"ok": 1, "html": template.render(context)}), mimetype="application/json") # No formset is found. Therefore, we conclude this is the first step. object = request.POST.get("object", request.GET.get("object", "")) if not object in ("user", "group"): log(3, "accounts_app - account add", "An alien object type '%s' has been spotted" % object) return HttpResponseBadRequest() # Create a new formset cache.delete(formset_id) formset_id = gen_formset_id(CACHE_FORMSET[action], object) form_obj = get_form(object, action, 1) if action == "add": data = {} form = form_obj() else: # action == "edit" if object == "user": account_obj = WenixUser.objects.get(pk=instance_id) data = {"groups": map(lambda x: str(int(x)), account_obj.groups.all().values_list("id", flat=True))} form = form_obj(instance=account_obj) else: # object == "group" account_obj = WenixGroup.objects.get(pk=instance_id) data = {"users": map(lambda x: str(int(x)), WenixUser.objects.filter(groups__name=account_obj.name).values_list("id", flat=True))} form = form_obj(initial=data) # An ugly way to initialize users list if object == "group": form["users"].field.choices = id_and_name_to_dict(request.user, mode, "user") cache.set(formset_id, {"object": object, "step": 1, "data": data}) response = render_to_response(TEMPLATE_FORM_PATH % object, {"form": form, "step": 1, "action": action, "object": account_obj}) response.set_cookie("formset_id", formset_id, FORMSET_ID_MAXAGE) return response
def record(request, mode, zone_name, action): data = json.loads(request.REQUEST.get('data', "{}")) form = BindForm.get_form(zone_name) if form is None: # add operation for a slave zone requested return HttpResponseBadRequest() if request.method == 'GET': # requesting the form if action == "add": return render_to_response("bind/add_form_rr_%s.django.html" % form.TYPE, {"form": form(), "zone_name": zone_name}) elif action == "edit": # requesting the form record_name = request.GET.get('rrkey', None) rrtype = request.GET.get('rrtype', None) bind_daemon = Bind() zone_config = bind_daemon.zone_config(zone_name) records = zone_config.config.names[record_name].records(rrtype).get_items() return render_to_response("bind/edit_form_rr.django.html", { "records": records, "type": rrtype, "record": record_name, "zone_name": zone_name}) else: if action != "delete": # delete actions are GET requests return HttpResponseBadRequest() if form.TYPE == BindForm.ZONE_STRAIGHT or form.TYPE == BindForm.ZONE_REVERSE: if action == "add": data["zone_name"] = zone_name # submitting the form form = form(data) if not form.is_valid(): return HttpResponse(json.dumps({"ok": 0, "errors": get_errors(form, data)}), mimetype="application/json") bind_daemon = Bind() # making shortcuts for key data rrkey = form.cleaned_data['rrkey'] # name rrtype = form.cleaned_data['rrtype'] # type rrvalue = form.cleaned_data['rrvalue'] # resolve zone_config = bind_daemon.zone_config(zone_name) zone_config.config.add_name(rrkey) zone_config.config.names[rrkey].records(rrtype, create=True).add(str(rrvalue)) zone_config.config.save(autoserial=True) # Checking whether we need to create a reversed record for straight A-records if data["rrtype"] == "A" and request.POST.get('create_reversed', False): reverse_form = BindReverse({"rrvalue": rrkey, "rrkey": rrvalue, "zone_name": "in-addr.arpa"}) if reverse_form.is_valid(): rrkey = reverse_form.cleaned_data['rrkey'] rrvalue = reverse_form.cleaned_data['rrvalue'] rrtype = form.cleaned_data['rrtype'] zone_name_reverse = bind_daemon.get_zone_name_by_ip(rrvalue) zone_config = bind_daemon.zone_config(zone_name_reverse) zone_config.config.add_name(rrkey) zone_config.config.names[rrkey].records(rrtypem,create=True).add(str(rrvalue)) zone_zonfig.config.save(autoserial=True) else: # Automatic PTR writing has failed log(2, "bind_app - record add", \ "Failed to write a reverse record. Data are: name='%s',resolve='%s'" % (rrkey, rrvalue)) return HttpResponse(json.dumps({"ok": 1, "errors": ""}), mimetype="application/json") data["rrkey"] = request.REQUEST.get('rrkey', None) data["rrtype"] = request.REQUEST.get('rrtype', None) if action == "edit": _data = {'rrtype': data['rrtype'], 'rrkey': data['rrkey'], 'zone_name': zone_name} errors = {} clean_data = [] for rrvalue_key in data: re_index = re.search("rrvalue_(\d+)", rrvalue_key) if not re_index: continue index = re_index.group(1) _data["rrvalue"] = data[rrvalue_key] _data['priority'] = data.get("priority_%s" % index, None) _form = form(_data) if _form.is_valid(): clean_data.append(_form.cleaned_data["rrvalue"]) else: _errors = get_errors(_form, _data) for e in _errors: errors["%s_%s" % (e, index)] = _errors[e] if errors: return HttpResponse(json.dumps({"ok": 0, "errors": errors}), mimetype="application/json") if len(clean_data) != 0: bind_daemon = Bind() zone_config = bind_daemon.zone_config(zone_name) records = zone_config.config.names[data['rrkey']].records(data['rrtype']) for item in records.get_items(): records.delete(item) for rrvalue in clean_data: records.add(str(rrvalue)) zone_config.config.save(autoserial=True) error = _("The zone '%(zone_name)s' has been changed") % {"zone_name": zone_name} return HttpResponse(json.dumps({"ok": 1, "error": error}), mimetype="application/json") else: # data is empty. meaning delete the record errors = {"general": _("At least on value is required for the record '%(rrkey)s'") % {"rrkey": data['rrkey']}} return HttpResponse(json.dumps({"ok": 0, "errors": errors}), mimetype="application/json") if action == "delete": if request.GET.get("flag", None) == "info": msg = _('Are you sure you want to delete the %(type)s-record "%(name)s"?' % {"name": data["rrkey"],"type": data["rrtype"]}) return HttpResponse(json.dumps({"confirm": msg}), mimetype="application/json") bind_daemon = Bind() zone_config = bind_daemon.zone_config(zone_name) names = zone_config.config.get_names() if data["rrkey"] in names: zone_config.config.delete_name(data["rrkey"]) zone_config.config.save(autoserial=True) return HttpResponse(json.dumps({"ok": 1, "error": _("The zone '%(zone_name)s' has been changed") % {"zone_name": zone_name}}), mimetype="application/json") elif form.TYPE == BindForm.FORWARD or form.TYPE == BindForm.HINT: # submitting the form if action == "add": form = form(data) if not form.is_valid(): return HttpResponse(json.dumps({"ok": 0, "errors": get_errors(form, data)}), mimetype="application/json") # making shortcuts for key data ipaddress = form.cleaned_data['ipaddress'] priority = int(form.cleaned_data['priority']) bind_daemon = Bind() named_zone = bind_daemon.get_zone(zone_name) forwarders = named_zone.get("forwarders", SortedDict()) # sorting the forwarders according to the priority i = 0 for forwarder in forwarders: i += 1 forwarders[forwarder] = i forwarders[ipaddress] = priority - 0.5 new_forwarders = SortedDict(sorted(forwarders.items(), key=lambda x:x[1])) # transforming to an appropriate format for forwarder in new_forwarders: new_forwarders[forwarder] = True named_zone["forwarders"] = new_forwarders bind_daemon.set_zone(zone_name, named_zone) bind_daemon.config.save() return HttpResponse(json.dumps({"ok": 1, "errors": ""}), mimetype="application/json") elif action == "type": # Changing zone type bind_daemon = Bind() named_zone = bind_daemon.get_zone(zone_name) if data["zone_type"] == "hint": named_zone["type"] = "hint" named_zone["file"] = BindConfig.ROOT_ZONE_PATH if "forwarders" in named_zone: del named_zone["forwarders"] if "forward" in named_zone: del named_zone["forward"] elif data["zone_type"] == "forward": # type == "forward" if "file" in named_zone: del named_zone["file"] named_zone["type"] = "forward" named_zone["forward"] = "only" if not "forwarders" in named_zone: named_zone["forwarders"] = {} else: return HttpResponse(json.dumps({"ok": 1, "errors": _("Not implemented")}), mimetype="application/json") bind_daemon.set_zone(zone_name, named_zone) bind_daemon.config.save() return HttpResponse(json.dumps({"ok": 1, "errors": ""}), mimetype="application/json") elif action == "delete": if request.GET.get("flag", None) == "info": msg = _('Are you sure you want to delete the forward server "%(name)s"?' % {"name": request.REQUEST.get("rrkey", "")}) return HttpResponse(json.dumps({"confirm": msg}), mimetype="application/json") bind_daemon = Bind() named_zone = bind_daemon.get_zone(zone_name) forwarders = named_zone.get("forwarders", SortedDict()) forwarder = request.REQUEST.get('rrkey', None) if forwarder in forwarders: del forwarders[forwarder] named_zone["forwarders"] = forwarders bind_daemon.set_zone(zone_name, named_zone) bind_daemon.config.save() return HttpResponse(json.dumps({"ok": 1, "error": _("The zone '%(zone_name)s' has been changed") % {"zone_name": zone_name}}), mimetype="application/json") else: # unrecognized request return HttpResponseBadRequest() #bind_daemon = Bind() #zone_config = bind_daemon.zone_config(zone_name) #include_file = bind_daemon.check_includefile(ZONE_INCLUDE_FILE % zone_name) """
def ftp_client(request, mode): path = urllib.url2pathname(request.POST.get("dir", request.GET.get("dir", "/"))) action = request.POST.get("action", request.GET.get("action", "show")) flag = request.POST.get("flag", request.GET.get("flag", None)) proftpd = Proftpd(request.user) ftp_client = proftpd.path(path) if not ftp_client.path_is_valid(): return HttpResponseBadRequest() """ The user is making a request which need a form to be filled in. """ if request.method == "GET": action = request.GET.get("action", "show") if action == "mkdir": return render_to_response("proftpd/window_mkdir.django.html") elif action == "upload": return render_to_response("proftpd/window_upload.django.html") elif action == "change_permission": if request.user.is_superuser: users = Users.objects.all() groups = unique(Groups.objects.all().values_list("groupname", flat=True)) else: users = ftp_client.ftp_user.peers() groups = ftp_client.ftp_user.groups() permissions = ftp_client.permissions() print permissions["all"] return render_to_response("proftpd/window_perm_change.django.html", {"selected_groups": permissions["group"], "selected_users": permissions["user"], "default": permissions["all"][""], "users": users, "groups": groups}) else: return render_to_response("proftpd/ftp_client.django.html", {"content": ftp_client.dir()}, context_instance=RequestContext(request)) else:# request == "POST" if action == "show": template = get_template("proftpd/browser.django.html") context = Context({"content": ftp_client.dir()}) return HttpResponse(template.render(context), mimetype="text/html") elif action == "info": template = get_template("proftpd/info_browser.django.html") context = Context({"info": ftp_client.info()}) return HttpResponse(template.render(context), mimetype="text/html") elif action == "change_permission": # Getting the permissions given according to the following scheme: # {"default": perm1, "user": {user1: perm2, user2: perm3}, "group": # {group1: perm4}} permissions = request.POST.get("permissions", None) if permissions: try: data = json.loads(permissions) except: # Damn... returng an error return HttpResponse(json.dumps({"ok": 0, "msg": _("Error occurred while serializing permissions")}), mimetype="application/json") # Setting he new permissions ftp_client.set_permissions(data) # Updating the config if not proftpd.update_config(): return HttpResponse(json.dumps({"ok": 0, "msg": _("Error occurred while saving the new configuration")}), mimetype="application/json") if ftp_client.is_dir: msg = _("The directory's permissions have been changed") else: msg = _("The file's permissions have been changed") return HttpResponse(json.dumps({"ok": 1, "msg": msg}), mimetype="application/json") elif action == "delete": if flag == "info": if ftp_client.is_file: msg = _('Are you sure you want to delete the file "%(name)s"?' % {"name": ftp_client.name}) else: msg = _('Are you sure you want to delete the directory "%(name)s"? The contents of the directory will also be deleted.' % {"name": ftp_client.name}) return HttpResponse(json.dumps({"confirm": msg}), mimetype="application/json") else: return HttpResponse(json.dumps(ftp_client.delete()), mimetype="application/json") elif action == "mkdir": name = request.POST.get("name", "New Folder") return HttpResponse(json.dumps(ftp_client.mkdir(name)), mimetype="application/json") elif action == "upload": response = ftp_client.upload(request.FILES['file'], \ request.META['REMOTE_ADDR']) return HttpResponse(response, mimetype='text/html') elif action == "download": if ftp_client.has_perm("READ", ftp_client.path) and ftp_client.is_file: return HttpResponse(json.dumps({"ok": 1, "redir": FTP_FILES_URL % ftp_client.download(request.META['REMOTE_ADDR'])}), mimetype="application/json") else: return HttpResponse(json.dumps({"ok": 0, "msg": _("Access denied")}), mimetype="application/json") else: log(3, "proftpd_app - ftp_client", "Strange action '%s'" % action) return HttpResponseBadRequest()
def connections(self): """ pid - PID un - username t_conn - connection time actn - action loc - location host - hostname ip_addr - IP address """ status = {} raw_status = commands.getoutput("ftpwho -v -o oneline -f /var/run/proftpd.scoreboard") lines = raw_status.split("\n") re_srv_status = re.search("(standalone|inetd).+?\[(\d+)\].*up\s+for\s+(.*)", lines.pop(0)) if re_srv_status: status["server"] = {"mode": re_srv_status.group(1), "pid": re_srv_status.group(2), "uptime": re_srv_status.group(3)} else: status["server"] = {"mode": "unknown","pid": "unknown","uptime": "unknown"} total = lines and re.search("(\d+)\s+users", lines.pop()) or [] if total: status["total"] = total.group(1) else: status["total"] = "0" status["users"] = {} for line in lines: for re_t in [self.re_idle, self.re_auth, self.re_actn]: if re_t.search(line): found = map(lambda x: x.strip(), re_t.match(line).groups()) if re_t == self.re_actn: ip_addr = None host = None pid, un, t_conn, actn, loc = found elif re_t == self.re_auth: actn = "AUTH" un = None loc = None pid, t_conn, host, ip_addr = found elif re_t == self.re_idle: #actn = "IDLE" pid, un, t_conn, actn, host, ip_addr, loc = found actn = actn.upper() if not un in status["users"]: status["users"][un] = [] status["users"][un].append({"action": actn, "pid": pid, "conn_time": t_conn, "hostname": host, "ip_address": ip_addr, "location": loc}) break else: log(8, "Proftpd Daemon - connections", "An ambigious line: %s" % line) return status
def statistics(request, mode): search = request.GET.get("value", None) period_str = request.GET.get("period", request.POST.get("period", None)) order_by = request.GET.get("order_by", "username") username = request.POST.get("username", None) data = {"mode": mode} traffic = Traffic.objects.all() # Checking if we were given "period" or "search" variables and setting a # template accordingly if period_str or search: template = "proftpd/search.django.html" else: # Default values template = "proftpd/statistics.django.html" start, end = map(lambda x: x.strftime("%d.%m.%Y"), (datetime.now()-timedelta(10), datetime.now())) period_str = "%s - %s" % (start, end) return render_to_response(template, {"period": period_str}, context_instance=RequestContext(request)) if period_str: period = [] date_format = "([\d\.]+)\s*-\s*([\d\.]+)" str_dates = re.search(date_format, period_str) for str_date in str_dates.groups(): re_dates = re.search("(\d{1,2})\.(\d{1,2})\.(\d{4})", str_date) if not re_dates: return HttpResponseBadRequest() day, month, year = map(lambda x: int(x), re_dates.groups()) period.append(datetime(year, month, day)) if period[0] == period[1]: period[1] += timedelta(hours=23, minutes=59, seconds=59) else: return HttpResponseBadRequest() data['statistics'] = [] if mode == "self": users = (request.user, ) elif mode == "group": users = request.user.peers() elif mode == "global": users = Users.objects.all() else: log(3, "proftpd_app - statistics", "Strange statistics mode '%s'" % mode) return HttpResponseBadRequest() today = date.today() if username: template = "proftpd/statistics_detail.django.html" cached_traffic = TrafficCache.objects.filter(username=username, date__range=period) data["statistics"] = Traffic.objects.filter(transfersize__gt=0, cache__in=cached_traffic).order_by("transferdate") else: # Checking whether the end period is today. If True we've got to overwrite the cache. if datetime.date(period[1]) == today: cached_to_delete = TrafficCache.objects.filter(date=today) traf = Traffic.objects.filter(transfersize__gt=0, cache__in=cached_to_delete).update(cache=None) cached_to_delete.delete() # Going through the users to calculate the traffic and cache it. for user in users: if search and not re.search(search, user.username, re.I): continue else: cached_traffic = TrafficCache.objects.filter(username=user.username, date__range=period) upload, download = 0, 0 for cached_traf in cached_traffic: download += int(cached_traf.download) upload += int(cached_traf.upload) upload_extra, download_extra = 0, 0 cached_dates = cached_traffic.values_list("date", flat=True) start_datetime = period[0] while start_datetime <= period[1]: end_datetime = start_datetime + timedelta(hours=23, minutes=59, seconds=59) current_date = datetime.date(start_datetime) if not current_date in cached_dates: # Go through all the traffic, counting and caching on the way traffic = Traffic.objects.filter(username=user.username, transfersize__gt=0, transferdate__range=(start_datetime, end_datetime)) # Caching traffic for future use new_cache = TrafficCache.objects.create(username=user.username, date=current_date) upld, downld = 0, 0 for traf in traffic: if traf.transfertype == "STOR": upld += traf.transfersize elif traf.transfertype == "RETR": downld += traf.transfersize traf.cache = new_cache traf.save() new_cache.upload, new_cache.download = str(upld), str(downld) new_cache.save() upload_extra += upld download_extra += downld start_datetime = end_datetime + timedelta(seconds=1) data['statistics'].append({"username": user.username, "download": download+download_extra, "upload": upload+upload_extra}) return render_to_response(template, data, context_instance=RequestContext(request))