Trying to set up a mail server in OpenBSD: doveadm auth login fails - imap

I set up an OpenBSD 7.0 instance on Vultr in order to get a mail server running with Dovecot and OpenSMTPD. I (mostly) followed the instructions here and here and a bit here.
I set it up to use with virtual mail, creating files in '/etc/mail/virtual' and '/etc/mail/credentials' with a single virtual user: 'user#domain.ca::vmail:2000:2000:/var/vmail/domain.ca/user::userdb_mail=maildir:/var/vmail/domain.ca/user'
I created the encrypted password with 'smtpctl encrypt' and pasted it where it should be in the credentials file.
However, running 'doveadm auth login user#domain.ca' fails.
In /var/log/maillog I get:
Jan 25 14:06:58 vultrBSD dovecot: auth-worker(165): conn unix:auth-worker (pid=44111,uid=518): auth-worker<1>: bsdauth(user#domain.ca): unknown user
Jan 25 14:06:58 vultrBSD dovecot: auth: passwd-file(user#domain.ca): Password mismatch
I know the password is correct, and I tried changing it and pasting in a new one that I created with 'smtpctl encrypt', but still the same error. The '/etc/mail/credentials' file is set to 0440 and owned by _smtpd:_dovecot. Even temporarily setting it to 0777 doesn't work.
I can send mail to the server from another account, I see that is shows up in '/var/vmail/domain.ca/user/new' but I am unable to connect my Thunderbird client to the server. Attempting to set up a new mail account in Thunderbird doesn't seem to work, Thunderbird rejects the password (although it does detect the correct protocols and ports, IMAP/SMTP).
Here is the local.conf file in /etc/dovecot:
auth_debug_passwords = yes
auth_mechanisms = plain
first_valid_uid = 2000
first_valid_gid = 2000
mail_location = maildir:/var/vmail/%d/%n
mail_plugin_dir = /usr/local/lib/dovecot
managesieve_notify_capability = mailto
managesieve_sieve_capability = fileinto reject envelope encoded-character vacation subaddress comparator-i;ascii-numeric relational regex imap4flags copy include variables body enotify environment mailbox date index ihave duplicate mime foreverypart extracttext imapsieve vnd.dovecot.imapsieve
mbox_write_locks = fcntl
mmap_disable = yes
namespace inbox {
inbox = yes
location =
mailbox Archive {
auto = subscribe
special_use = \Archive
}
mailbox Drafts {
auto = subscribe
special_use = \Drafts
}
mailbox Junk {
auto = subscribe
special_use = \Junk
}
mailbox Sent {
auto = subscribe
special_use = \Sent
}
mailbox Trash {
auto = subscribe
special_use = \Trash
}
prefix =
}
plugin {
imapsieve_mailbox1_before = file:/usr/local/lib/dovecot/sieve/report-spam.sieve
imapsieve_mailbox1_causes = COPY
imapsieve_mailbox1_name = Junk
imapsieve_mailbox2_before = file:/usr/local/lib/dovecot/sieve/report-ham.sieve
imapsieve_mailbox2_causes = COPY
imapsieve_mailbox2_from = Junk
imapsieve_mailbox2_name = *
sieve = file:~/sieve;active=~/.dovecot.sieve
sieve_global_extensions = +vnd.dovecot.pipe +vnd.dovecot.environment
sieve_pipe_bin_dir = /usr/local/lib/dovecot/sieve
sieve_plugins = sieve_imapsieve sieve_extprograms
}
protocols = imap sieve
service imap-login {
inet_listener imaps {
port = 993
}
}
service managesieve-login {
inet_listener sieve {
port = 4190
}
inet_listener sieve_deprecated {
port = 2000
}
}
ssl_cert = </etc/ssl/domain.ca.fullchain.pem
ssl_key = </etc/ssl/private/domain.ca.key
userdb {
args = username_format=%u /etc/mail/credentials
driver = passwd-file
name =
}
passdb {
args = scheme=CRYPT username_format=%u /etc/mail/credentials
driver = passwd-file
name =
}
protocol imap {
mail_plugins = " imap_sieve"
}
Has anyone else experienced this and know of a fix?
Thanks.

Hashed strings, including passwords, typically use several layers besides the base hashing algorithm. Two different implementations (dovecot vs smtpd) using the same hashing algorithm will output two different hashes given the same input (password.)
This is due to what is called salt and pepper. Salt is a randomly generated string usually based on some user data as the seed. This salt is then inserted into the password in a way dictated by the implementation (dovecot or smtpd) before hashing the password.
Similarly, pepper is a string dictated by the implementation and inserted into the password before hashing. This combination of salting and peppering creates a unique hash per implementation which makes storing passwords safer. This makes it so that a cracker can't easily compare hashes from several sites or programs to crack user passwords and break into all instances of that password simultaneously.
This is why you can't reuse a password hash stored by one program to unlock the same password when used by another program. Even if both programs use identical hashing algorithms.
The fix should be to set up the credentials individually for each program and not reuse each other's hashes.

Related

MQTT block specific client from connecting via TLS

I have MQTT (VerneMQ) setup with TLS authentication. Also I have setup frequent pulling
CRL (certificate revocation list) from CA (Private). I am able to revoke the specific client certificate to blocking it from connecting to MQTT.
There is one certificate which is shared & I don't want to revoke but also don't want client to be able to authenticate with MQTT. Following is my configuration
DOCKER_VERNEMQ_ACCEPT_EULA = "yes"
MY_POD_NAME = "vernemq"
DOCKER_VERNEMQ_KUBERNETES_APP_LABEL = "vernemq"
DOCKER_VERNEMQ_LOG__CONSOLE__LEVEL = "debug"
DOCKER_VERNEMQ_KUBERNETES_LABEL_SELECTOR = "app=vernemq"
DOCKER_VERNEMQ_LISTENER__TCP__ALLOWED_PROTOCOL_VERSIONS = "3,4,5"
DOCKER_VERNEMQ_ALLOW_ANONYMOUS = "on"
DOCKER_VERNEMQ_KUBERNETES_INSECURE = "1"
DOCKER_VERNEMQ_MAX_ONLINE_MESSAGES = "-1"
DOCKER_VERNEMQ_MAX_OFFLINE_MESSAGES = "-1"
DOCKER_VERNEMQ_MAX_INFLIGHT_MESSAGES = "0"
DOCKER_VERNEMQ_LISTENER__TCP__DEFAULT = "0.0.0.0:1883"
DOCKER_VERNEMQ_LISTENER__SSL__DEFAULT = "0.0.0.0:8883"
DOCKER_VERNEMQ_LISTENER__WS__DEFAULT = "0.0.0.0:8080"
DOCKER_VERNEMQ_LISTENER__HTTP__METRICS = "0.0.0.0:8888"
DOCKER_VERNEMQ_LISTENER__HTTP__DEFAULT = "0.0.0.0:8888"
DOCKER_VERNEMQ_LISTENER__SSL__REQUIRE_CERTIFICATE = "on"
# DOCKER_VERNEMQ_LISTENER__SSL__USE_IDENTITY_AS_USERNAME = "on"
DOCKER_VERNEMQ_LISTENER__SSL__CAFILE = "/vernemq/cert/ca.crt"
DOCKER_VERNEMQ_LISTENER__SSL__CERTFILE = "/vernemq/cert/server.crt"
DOCKER_VERNEMQ_LISTENER__SSL__KEYFILE = "/vernemq/cert/server.key"
DOCKER_VERNEMQ_LISTENER__SSL__CRLFILE = "/tmp/shared/ca.crl"
DOCKER_VERNEMQ_ALLOW_REGISTER_DURING_NETSPLIT = "on"
DOCKER_VERNEMQ_ALLOW_PUBLISH_DURING_NETSPLIT = "on"
DOCKER_VERNEMQ_ALLOW_SUBSCRIBE_DURING_NETSPLIT = "on"
DOCKER_VERNEMQ_ALLOW_UNSUBSCRIBE_DURING_NETSPLIT = "on"
Any way I can block the specific client certificate ?
I'm not familiar with vernemq's specific options but why not just set up the ACL to block the user represented by that certificate from being able to subscribe or publish to any topics.
Clients would still be able to connect with that shared certificate, but would not be able to receive or publish any messages.
To make this work you would probably have to use the Certificate identity as the User name (but you appear to have commented that out of the env vars you have shown in the question)

Service Principal Creation by Terraform doesn't provide password/secret in the output

when generating Service Principal in Azure manually, as a result of the operation I'm provided a password.
It's not the case however if I create service principal with Terraform, the password is not among the outputs of this module:
+ azuread_service_principal.k8s_principal
id: <computed>
application_id: "${azuread_application.app.application_id}"
display_name: <computed>
Is there anything I missed? Why does the Terraform behavior differs in the output compared to CLI?
password is required INPUT to the azuread_service_principal_password block. As such, you can generate a random password and export it yourself. Complete Terraform code is something like this:
resource "azuread_application" "app" {
name = "${local.application_name}"
}
# Create Service Principal
resource "azuread_service_principal" "app" {
application_id = "${azuread_application.app.application_id}"
}
resource "random_string" "password" {
length = 32
special = true
}
# Create Service Principal password
resource "azuread_service_principal_password" "app" {
end_date = "2299-12-30T23:00:00Z" # Forever
service_principal_id = "${azuread_service_principal.app.id}"
value = "${random_string.password.result}"
}
output "sp_password" {
value = "${azuread_service_principal_password.app.value}"
sensitive = true
}
to who using newer version of Terraform, you don't need to preset the password, following code is working fine:
resource "azuread_service_principal_password" "auth_pwd" {
service_principal_id = azuread_service_principal.auth.id
}
output "auth_client_secret" {
value = azuread_service_principal_password.auth_pwd.value
description = "output password"
sensitive = true
}
then you can run the following cli to retrieve the password:
terraform output -raw auth_client_secret
tested on terraform 1.0.10, hashicorp/azuread provider 2.11
In the terraform document, the azuread_service_principal block only defines the Argument application_id and Attributes id, display_name, So you only could see these resources. Also, the azuread_service_principal_password block allows you to export the Key ID for the Service Principal Password. You still could not see the real password.
In the Azure CLI az ad sp create-for-rbac has an optional parameter --Password. So you could see the password output.

How can I integrate ASP pages and queries into an iOS app?

I have a rather puzzling scenario right now, of figuring out how to integrate several large queries (many different items for each) into an iOS app that communicates with a C#-based REST API. I am trying to pull up several reports in the app, and if I recreate all these queries within the API along with recreating the interface in iOS, it could be quite time-consuming. The page that accesses the reports is a classic ASP page and includes a security header to ensure that the user session has been validated through the login page. Is there a way to set this up as a UIWebView and somehow validate a session upon loading of the UIWebView? Otherwise it will be quite a long, arduous process.
Could a cookie possibly be transferred over after the user has logged in using NSURLRequest to the UIWebView?
Each page has code to check if the session is authenticated
<%
if Session("portallogin") <> "good" then
response.redirect("example.com")
end if
%>
Here is some of the relevant login code that is responsible for initial authentication
'Get the username and password sent as well as user ip
On Error resume next
Session("login") = "bad" 'init to bad
sent_username = Request("username")
sent_password = Request("password")
source = Request.form("source")
remember_me = Request("remember_me")
userip = Request.ServerVariables("REMOTE_ADDR")
sent_username = replace(sent_username,"'","'")
sent_username = protectval(sent_username)
sent_password = protectval(sent_password)
if rs.BOF and rs.EOF then
Session("login") = "bad"
response.cookies("user")("name") = ""
response.Cookies("user")("pword") = ""
else
arr = rs.GetRows()
password = arr(0,0)
memberid = arr(1,0)
expired = arr(2,0)
if sent_password = password then
Session("login") = "good"
if expired = "True" Then
%>
'''''''''''''''''''
if session is good
'''''''''''''''''''
Session("username") = sent_username
Session("maintuser") = sent_username
Session("b2buser") = sent_username
Session("password") = sent_password
Session("memberid") = memberid
Session("customernumber") = customernumber
Session("cno") = cno
Session("login") = "good"
if remember_me = "on" Then
response.cookies("entry")("doorway") = cook(sent_username)
response.Cookies("entry")("michael") = cook(sent_password)
response.Cookies("entry")("remember_me") = cook("CHECKED")
Response.Cookies("entry").Expires = Now() + 365
else
response.cookies("entry")("doorway") = ""
response.Cookies("entry")("michael") = ""
response.Cookies("entry")("remember_me") = ""
Response.Cookies("entry").Expires = Now() + 5
end if
As most of the parameters reference the Request collection you could put the parameters in the querystring and thus make them part of the base url for UIWebView. So your URL request would look like
file.asp?username=xxx&password=yyy&source=zzz&remember_me=on
you would need to change line 7 in your sample file to be
source = Request("source")
but it would still work for existing requests.
The obvious problem with this code is that you have a username and password stored in your app which could be intercepted and abused. So be aware of that. I would not recommend this approach.
A better solution would be to consider rewriting the login function to store a temporary GUID and a timestamp in the database which could then be passed in the request as part of the querystring. Your authentication code could then be modified to check if that GUID is valid and update the timestamp associated with the GUID (or check for the session if they are using the old access method for that page).

How can I access a raw private paste from pastebin?

I know how to generate a user key using the pastebin API, but how can I use this userkey to access a raw private paste?
I am using Lua for this.
Obtaining the raw paste bin output is not part of of the Pastebin API:
This option is actually not part of our API, but you might still want to use it. To get the RAW output of a paste you can use our RAW data output URL:
http://pastebin.com/raw.php?i=
Simply add the paste_key at the end of that URL and you will get the RAW output.
Since private pastes can only be seen by the user who created them, my guess is that they use the logincookie for authentication. In that case, you'll need to send it with the HTTP request.
In respect to implementing this in Lua, (since you haven't said which library you're using) I'm gonna go forth and recommend the HTTP module in LuaSocket or the wonderful Luvit (http://luvit.io).
Here is a ready example of the code for you:
local https = require('ssl.https')
https.TIMEOUT= 15
local private_raw_url="https://pastebin.com/raw/YOURPAGE" -- Change raw link
local user_name, user_password = "USER", "PASS" -- and user with password
local request_body = "submit_hidden=submit_hidden&user_name=".. user_name .. "&user_password=" .. user_password .. "&submit=Login"
local resp = {}
local res, code, headers, status = https.request ( {
method = 'POST',
url = "https://pastebin.com/login",
headers = {
Host = "pastebin.com",
["Content-Type"] = "application/x-www-form-urlencoded",
["Content-Length"] = string.len(request_body),
Connection = "keep-alive",
},
source = ltn12.source.string(request_body),
sink = ltn12.sink.table(resp),
protocol = "tlsv1",
verify = "none",
verifyext = {"lsec_continue", "lsec_ignore_purpose"},
options = { "all", "no_sslv2", "no_sslv3" }
} )
if not headers['set-cookie']:find('pastebin_user') then
print('bad login')
return
end
resp={}
local cookie = headers['set-cookie'] or ''
local cookie1, cookie2, cookie3 = cookie:match("(__cfduid=%w+; ).*(PHPSESSID=%w+; ).*(pastebin_user=%w+; )" )
if cookie1 and cookie2 and cookie3 then
cookie = cookie1 .. cookie2 .. cookie3
body, code, headers= https.request{
url = private_raw_url ,
headers = {
--Host = "pastebin.com",
['Cookie'] = cookie,
['Connection'] = 'keep-alive'
},
sink = ltn12.sink.table(resp)
}
if code~=200 then return end
print( table.concat(resp) )
else
print("error match cookies!" )
end
I know that this is a little late to answer the question but I hope this will help someone later on.
If you want to access raw private pastes, you will first need to list the pastes that the user has created. This is a part of the API. This requires the user to be logged in.
With this API you can list all the pastes created by a certain user.
You will need send a valid POST request to the URL below to access the
data:
http://pastebin.com/api/api_post.php
The response that you will get will be an XML response, as follows:
<paste>
<paste_key>0b42rwhf</paste_key>
<paste_date>1297953260</paste_date>
<paste_title>javascript test</paste_title>
<paste_size>15</paste_size>
<paste_expire_date>1297956860</paste_expire_date>
<paste_private>0</paste_private>
<paste_format_long>JavaScript</paste_format_long>
<paste_format_short>javascript</paste_format_short>
<paste_url>http://pastebin.com/0b42rwhf</paste_url>
<paste_hits>15</paste_hits>
</paste>
Once you have that, parse the XML to get the paste_key and the paste_private. You need to check the value of paste_private because you want private pastes only. The documentation says:
We have 3 valid values available which you can use with the
'api_paste_private' parameter:
0 = Public
1 = Unlisted
2 = Private (only allowed in combination with api_user_key, as you have to be logged into your account to access the paste)
So, if your paste has paste_private set to 2, get the paste_key for it.
Once you have the paste_key, use the API call to get the RAW paste. No username or password required once you have the paste key for the private paste.
Have fun!

How to authenticate to Active Directory using iOS app

I am trying to create and iOS app that takes a users credentials and verifies it with the AD server. Is there some built in library in xCode to do that, or is it third party?
Any advice on direction to look would be greatly appreciated.
Thanks
Zach
Ok, so this was the PHP i used to make the connection to the ldap server. i am not 100% sure what is happening here, i got this code from IT Coordinator at my company. I understand all the binding and searching parts, but i dont get the the ldap_set_option part of this whole thing. Anyway after setting it up this way, you can then call the URL of the php script and pass it parameters. take a look at the PHP, and the url example with be below.
<?php
//Connection parameters
$dn = "DC=network,DC=net";
$host = "ldap://ldap.network.com";
$port = 1111
$user = $_GET['user'];
$pass = $_GET['pass'];
//$user = "user#network.net";
//$pass = "pass";
$filter = "memberof";
$keyword = "CN=USSC_ALL,CN=Users,DC=network,DC=net";
$filter = "objectclass";
$keyword = "user";
$filter = "objectcategory";
$keyword = "CN=Person,CN=Schema,CN=Configuration,DC=network,DC=net";
//The real thing with PHP
if (!empty($keyword) and !empty($dn)) {
//Connect to the AD
$adConn = ldap_connect($host, $port) or die("Could not connect!");
//Set protocol verison
ldap_set_option($adConn, LDAP_OPT_PROTOCOL_VERSION, 3) or die ("Could not set ldap protocol1");
//Set referrals... Won't work without this...
ldap_set_option($adConn, LDAP_OPT_REFERRALS, 0) or die ("Could not set ldap protocol2");
//Bind the user
$bd = ldap_bind($adConn, $user, $pass) or die ("Could not bind");
echo $bd;
//End binding
ldap_unbind($adConn);
} else {
echo "<p>No results found!</p>";
}
?>
</body>
</html>
Ok so now all you have to do is pass a username and password to the script and it will return the bind. that will give you either true or false. meaning if it bound successfully it is a correct combination of username and password.
this is how i am calling it:
http://192.268.192.1/ldap.php?user=(username here)&pass=(password here)
This is the approach that i took, and i think it is a very simple answer.
So what I have been able to find out is that i need to use PHP to do this. By creating a php file on the server, i can use built in ldap protocol to take a user name and password to the ldap server for verification. The query should then return true or false. As soon as i get this working ill post my code

Resources