Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot add/edit networks through Webui "The requested module does not acknowledge web requests" #1908

Closed
mwtzl opened this issue Apr 24, 2024 · 6 comments

Comments

@mwtzl
Copy link

mwtzl commented Apr 24, 2024

I'm using ZNC 1.8.2+deb3.1 on Debian-stable (installed via apt).

When trying to add or edit networks through the WebUI I get redirected to this 404 page:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<meta charset="UTF-8"/>
<title>404 Not Implemented</title>
</head>
<body>
<h1>Not Implemented</h1>
<p>The requested module does not acknowledge web requests</p>
<hr/>
<p>ZNC - <a href="[https://znc.in](view-source:https://znc.in/)">https://znc.in</a></p>
</body>
</html>

I am able to edit everything via controlpanel module, although it's a bit cumbersome compared to the webui sometimes.

I am running the WebUI through a reverse proxy, so maybe the issue lies here. It looks like this:

server {
  listen 443 ssl http2;
  listen [::]:443 ssl http2;

  server_name znc.***.***;

  ssl_protocols TLSv1.3;# Requires nginx >= 1.13.0 else use TLSv1.2
  ssl_prefer_server_ciphers on;
  ssl_dhparam /etc/nginx/dhparam.pem; # openssl dhparam -out /etc/nginx/dhparam.pem 4096
  ssl_ciphers EECDH+CHACHA20:EECDH+AESGCM:EDH+AESGCM;
  ssl_conf_command Ciphersuites TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256;
  ssl_conf_command Options PrioritizeChaCha;
  ssl_ecdh_curve secp384r1; # Requires nginx >= 1.1.0
  ssl_session_timeout  10m;
  ssl_session_cache shared:SSL:10m;
  ssl_session_tickets off; # Requires nginx >= 1.5.9
  ssl_stapling on; # Requires nginx >= 1.3.7
  ssl_stapling_verify on; # Requires nginx => 1.3.7
  resolver 1.1.1.1 1.0.0.1 valid=300s;
  resolver_timeout 5s;
  add_header X-Frame-Options SAMEORIGIN;
  add_header X-Content-Type-Options nosniff;
  add_header X-XSS-Protection "1; mode=block";

  ssl_certificate /etc/letsencrypt/live/***.***/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/***.***/privkey.pem;

  #auth_basic "What's the password?";
  #auth_basic_user_file /etc/htpasswd;
  
  location / {
      proxy_pass http://[::1]:7000$uri;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
}

Is there another place ZNC logs to that I can find out more?

@psychon
Copy link
Member

psychon commented Apr 26, 2024

Is there another place ZNC logs to that I can find out more?

Depends on how exactly you run ZNC, but in general, running with --debug provides some output.

When trying to add or edit networks through the WebUI I get redirected to this 404 page:

Could you say something about the URL that your browser displays when you get this 404 page? I don't want to know the (possibly private) location of your web interface, but the relative URL for that. Specifically, which module are you accessing?

For example, if your browser were to display https://znc.in/foo/bar, I'd be interested in the /foo/bar part of this.

Another quick idea: What do the nginx logs say for this request? Perhaps there is something helpful in its access logs.

@mwtzl
Copy link
Author

mwtzl commented Apr 26, 2024

I have provided the relevant part of my nginx log below. As you can see, the URL its trying to access is /mods/global/webadmin/addnetwork, but the same thing happens for editnetwork and delnetwork.

2003:d4:****:****:****:****:****:****- - [26/Apr/2024:09:35:34 +0000] "GET /mods/global/webadmin/addnetwork?user=*** HTTP/2.0" 404 269 "https://znc.***.***/mods/global/webadmin>

@psychon
Copy link
Member

psychon commented Apr 26, 2024

Well... okay, I don't know what is going and would be interested in hints from znc --debug.

2003:d4:****:****:****:****:****:****- - [26/Apr/2024:09:35:34 +0000] "GET /mods/global/webadmin/addnetwork?user=*** HTTP/2.0" 404 269 "https://znc.***.***/mods/global/webadmin>

How do I have to read this? nginx got a request for /mods/global/webadmin/addnetwork?user=***, I guess. But the /mods/global/webadmin at the end confuses me.

Looking at the code, The requested module does not acknowledge web requests comes from here:

"The requested module does not acknowledge web requests");

This code is reached if a module "does nothing" in its OnWebRequest hook. The default implementation does nothing, but the implementation from webadmin definitely should do something:

znc/modules/webadmin.cpp

Lines 519 to 736 in 82e82f0

bool OnWebRequest(CWebSock& WebSock, const CString& sPageName,
CTemplate& Tmpl) override {
std::shared_ptr<CWebSession> spSession = WebSock.GetSession();
if (sPageName == "settings") {
// Admin Check
if (!spSession->IsAdmin()) {
return false;
}
return SettingsPage(WebSock, Tmpl);
} else if (sPageName == "adduser") {
// Admin Check
if (!spSession->IsAdmin()) {
return false;
}
return UserPage(WebSock, Tmpl);
} else if (sPageName == "addnetwork") {
CUser* pUser = SafeGetUserFromParam(WebSock);
// Admin||Self Check
if (!spSession->IsAdmin() &&
(!spSession->GetUser() || spSession->GetUser() != pUser)) {
return false;
}
if (!pUser) {
WebSock.PrintErrorPage(t_s("No such user"));
return true;
}
if (spSession->IsAdmin() || !spSession->GetUser()->DenySetNetwork()) {
return NetworkPage(WebSock, Tmpl, pUser);
}
WebSock.PrintErrorPage(t_s("Permission denied"));
return true;
} else if (sPageName == "editnetwork") {
CIRCNetwork* pNetwork = SafeGetNetworkFromParam(WebSock);
// Admin||Self Check
if (!spSession->IsAdmin() &&
(!spSession->GetUser() || !pNetwork ||
spSession->GetUser() != pNetwork->GetUser())) {
return false;
}
if (!pNetwork) {
WebSock.PrintErrorPage(t_s("No such user or network"));
return true;
}
return NetworkPage(WebSock, Tmpl, pNetwork->GetUser(), pNetwork);
} else if (sPageName == "delnetwork") {
CString sUser = WebSock.GetParam("user");
if (sUser.empty() && !WebSock.IsPost()) {
sUser = WebSock.GetParam("user", false);
}
CUser* pUser = CZNC::Get().FindUser(sUser);
// Admin||Self Check
if (!spSession->IsAdmin() &&
(!spSession->GetUser() || spSession->GetUser() != pUser)) {
return false;
}
if (spSession->IsAdmin() || !spSession->GetUser()->DenySetNetwork()) {
return DelNetwork(WebSock, pUser, Tmpl);
}
WebSock.PrintErrorPage(t_s("Permission denied"));
return true;
} else if (sPageName == "editchan") {
CIRCNetwork* pNetwork = SafeGetNetworkFromParam(WebSock);
// Admin||Self Check
if (!spSession->IsAdmin() &&
(!spSession->GetUser() || !pNetwork ||
spSession->GetUser() != pNetwork->GetUser())) {
return false;
}
if (!pNetwork) {
WebSock.PrintErrorPage(t_s("No such user or network"));
return true;
}
CString sChan = WebSock.GetParam("name");
if (sChan.empty() && !WebSock.IsPost()) {
sChan = WebSock.GetParam("name", false);
}
CChan* pChan = pNetwork->FindChan(sChan);
if (!pChan) {
WebSock.PrintErrorPage(t_s("No such channel"));
return true;
}
return ChanPage(WebSock, Tmpl, pNetwork, pChan);
} else if (sPageName == "addchan") {
CIRCNetwork* pNetwork = SafeGetNetworkFromParam(WebSock);
// Admin||Self Check
if (!spSession->IsAdmin() &&
(!spSession->GetUser() || !pNetwork ||
spSession->GetUser() != pNetwork->GetUser())) {
return false;
}
if (pNetwork) {
return ChanPage(WebSock, Tmpl, pNetwork);
}
WebSock.PrintErrorPage(t_s("No such user or network"));
return true;
} else if (sPageName == "delchan") {
CIRCNetwork* pNetwork = SafeGetNetworkFromParam(WebSock);
// Admin||Self Check
if (!spSession->IsAdmin() &&
(!spSession->GetUser() || !pNetwork ||
spSession->GetUser() != pNetwork->GetUser())) {
return false;
}
if (pNetwork) {
return DelChan(WebSock, pNetwork);
}
WebSock.PrintErrorPage(t_s("No such user or network"));
return true;
} else if (sPageName == "deluser") {
if (!spSession->IsAdmin()) {
return false;
}
if (!WebSock.IsPost()) {
// Show the "Are you sure?" page:
CString sUser = WebSock.GetParam("user", false);
CUser* pUser = CZNC::Get().FindUser(sUser);
if (!pUser) {
WebSock.PrintErrorPage(t_s("No such user"));
return true;
}
Tmpl.SetFile("del_user.tmpl");
Tmpl["Username"] = sUser;
return true;
}
// The "Are you sure?" page has been submitted with "Yes",
// so we actually delete the user now:
CString sUser = WebSock.GetParam("user");
CUser* pUser = CZNC::Get().FindUser(sUser);
if (pUser && pUser == spSession->GetUser()) {
WebSock.PrintErrorPage(
t_s("Please don't delete yourself, suicide is not the "
"answer!"));
return true;
} else if (CZNC::Get().DeleteUser(sUser)) {
WebSock.Redirect(GetWebPath() + "listusers");
return true;
}
WebSock.PrintErrorPage(t_s("No such user"));
return true;
} else if (sPageName == "edituser") {
CString sUsername = SafeGetUsernameParam(WebSock);
CUser* pUser = CZNC::Get().FindUser(sUsername);
if (!pUser) {
if (sUsername.empty()) {
pUser = spSession->GetUser();
} // else: the "no such user" message will be printed.
}
// Admin||Self Check
if (!spSession->IsAdmin() &&
(!spSession->GetUser() || spSession->GetUser() != pUser)) {
return false;
}
if (pUser) {
return UserPage(WebSock, Tmpl, pUser);
}
WebSock.PrintErrorPage(t_s("No such user"));
return true;
} else if (sPageName == "listusers" && spSession->IsAdmin()) {
return ListUsersPage(WebSock, Tmpl);
} else if (sPageName == "traffic") {
return TrafficPage(WebSock, Tmpl);
} else if (sPageName == "index") {
return true;
} else if (sPageName == "add_listener") {
// Admin Check
if (!spSession->IsAdmin()) {
return false;
}
return AddListener(WebSock, Tmpl);
} else if (sPageName == "del_listener") {
// Admin Check
if (!spSession->IsAdmin()) {
return false;
}
return DelListener(WebSock, Tmpl);
}
return false;
}

Well... unless you are accessing a page it does not understand. All the return falses here could reach the code path you are seeing. Most of them are admin checks ("A non-admin is trying to do something that only admins may do"). I will assume that this is not the case for you.

Anyway, for your addnetwork case, this is the relevant code:

znc/modules/webadmin.cpp

Lines 537 to 556 in 82e82f0

} else if (sPageName == "addnetwork") {
CUser* pUser = SafeGetUserFromParam(WebSock);
// Admin||Self Check
if (!spSession->IsAdmin() &&
(!spSession->GetUser() || spSession->GetUser() != pUser)) {
return false;
}
if (!pUser) {
WebSock.PrintErrorPage(t_s("No such user"));
return true;
}
if (spSession->IsAdmin() || !spSession->GetUser()->DenySetNetwork()) {
return NetworkPage(WebSock, Tmpl, pUser);
}
WebSock.PrintErrorPage(t_s("Permission denied"));
return true;

The Admin or self change-check could produce the error message you are seeing. Besides that, I don't see anything that could cause this (all the other paths should display an error message), but I might be missing something. This might also be a problem with the HTTP session getting lost.

Does the webadmin web page still shows your login name after clicking around a bit? The session magic uses cookies and that should still work behind a proxy. But perhaps "something" is going on with your proxy. Did you configure TrustedProxies?

Anyway, now I would be more interested in output from znc --debug when doing such a request.

@mwtzl
Copy link
Author

mwtzl commented Apr 26, 2024

There is something weird going on with the webadmin for sure. The error happens when I'm trying to do changes on my own account, so while that one isn't an admin, it should still be allowed.

In fact, a different kind of silent error happens when trying to do stuff as admin from the webadmin interface. When trying to edit other accounts, I instead get redirected to the admin page instead. It shows /mods/global/webadmin/edituser?user=normalusername in the URL, but I'm clearly on the /mods/global/webadmin/edituser?user=admin page instead.

I have

TrustedProxy = 127.0.0.1
TrustedProxy = ::1

in my znc.conf.

I'll come back with znc --debug output later / tomorrow.

@psychon
Copy link
Member

psychon commented Apr 26, 2024

Could it be that the ?user=foo part gets lost between the proxy and znc?

I don't really understand it, but Google sounds like this is a not-unusual problem: https://serverfault.com/questions/656380/nginx-proxy-pass-with-uri-modification

@mwtzl
Copy link
Author

mwtzl commented Apr 26, 2024

Thanks for that link, that must have been it!

Changing proxy_pass http://[::1]:7000$uri; in the relevant nginx config to proxy_pass http://[::1]:7000; seems to have fixed the problem!

Closing this as resolved.

@mwtzl mwtzl closed this as completed Apr 26, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants