I’m working on a restricted-access control website in parallel to a public one. At the moment, all the user access and directory password setting is performed in cPanel, however cPanel’s a little confusing for some of the users. But we need in the restricted-access website to modify the list of authorised people who can access it (and some other parts of the website).
So I’m trying to set up a PHP script on the restricted access site to do something similar to cPanel to be able to edit the actual passwd files. However everything I’ve tried hasn’t worked. Our web server is LiteSpeed not apache (can’t change this due to shared host setup). It’s using passwd files in a folder outside of the web-accessible folder, referenced by the .htaccess files. Having looked at the existing accesses listed, I can see that it doesn’t appear to be using the salted MD5 hash that’s stated in the apache docs: the hashed password that’s stored is different to what I’m thinking I should expect (e.g. the salt is significantly more than 2 characters), and for security reasons I’m reluctant to embed a particular password hashing algorithm in my code. I’ve tried to use the htpasswd utility normally supplied with apache via exec or shell_exec, but it’s either not installed or not accessible (and I’ve tried several different paths – checking even for its existence by file_exists returned false in all cases, so hardly a surprise that none of the files changed!).
I’ve spent the last couple of days doing various searches through different sets of documentation to see what LiteSpeed and/or cPanel do, but mostly my searches bring up about cPanel login passwords not the user access control passwords. I’ve tried looking into some cPanel source code but had no luck finding anything.
If anyone’s got a more direct reference to some source code, or something in the documentation that describes how to run the password add/update/delete functionality in LiteSpeed, that would be wonderful. Even just some way to trigger the cPanel functionality more directly would be useful (I know it’s got an API but the path to it is locked down on my host).
Edit: After Steve’s comment, I went to check a couple of things. My scripts can see the passwd files regardless of the script’s directory placement. The passwd file has permissions 644 as I’d expect, I’m anticipating that the “user” that has the write permissions is the one I use to log into cPanel, which hopefully isn’t the username the server is running under… which presents additional difficulties.
Edit #2: I did an additional test where I created a temporary password-protected subdirectory, and then added a user directly from the PHP script (copy-paste one of the existing lines but changed the username). That worked fine, the new user was added, and cPanel even saw the change. So permissions not an issue.
Edit #3: I’ve done some playing about and got a string being output from crypt that mostly matches what is in the passwd file (I’ll add a warning message on the reset page to ensure the latest algorithm is used). However, the salt that crypt is looking for is $1$<8-char-rand-string>$ whereas what’s in the file is $apr1$<8-char-rand-string>$. Adding the “apr” in the salt causes crypt to fail 🙁 .
2
Answers
For future reference, my edit #3 was 95% of the way to the solution, which I've now managed to put in place and works. I eventually realised that I just need to drop the "apr" that htpasswd inserts somehow into the salt for algorithm selection, and just use the salt with the '$1$' before and '$' after. Writing that out to the passwd file along with the username gave me access and worked. The page includes a warning to future visitors to the page to ensure that the algorithm is updated when it needs to be.
The actual encryption code is: crypt($password, '$1$' . substr(str_replace('+', '.', base64_encode(openssl_random_pseudo_bytes(12))), 0, 8) . '$')
I'm hoping that my code is cryptographically secure enough. I've seen far too many code snippets where the salt is generated using mt_rand or equivalent... (insert shudder here)
Edit: Having answered this, I've since discovered the cPanel API PHP file isn't automatically installed. It's an extra you need to download, see https://github.com/CpanelInc/xmlapi-php. So I'm now playing around with that, and will probably scrub the code that I've done... but leaving it here in this answer for historical reasons or in the hope it helps someone else.
You can add deny/allow IPs in .htaccess in the directory,
or add some password protection rule for a particular directory in .htaccess.
something like: http://www.htaccesstools.com/articles/password-protection/