diff --git a/VERSION b/VERSION index 1ab36bc1..2454e1d2 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.93beta5 +0.93beta6 diff --git a/doc/cntlm.1 b/doc/cntlm.1 index 5921e348..d4a35fed 100644 --- a/doc/cntlm.1 +++ b/doc/cntlm.1 @@ -5,7 +5,7 @@ .SH SYNOPSIS .B cntlm [ -.B -AaBcDdFfgHhILlMPprSsTUuvw +.B -AaBcDdFfgHhILlMPprSsTUuvwXZ ] [ \fIhost1\fP \fIport1\fP | \fIhost1\fP:\fIport1\fP ] ... \fIhostN\fP \fIportN\fP .SH DESCRIPTION @@ -111,7 +111,7 @@ credentials and it is moderately easy to sniff them. .ne 6 IMPORTANT: HTTP protocol obviously has means to negotiate authorization before letting you through, but TCP/IP doesn't (i.e. open port is open port). If you use NTLM-to-basic and DON'T specify some username/password in -the configuration file, you are bound to loose tunneling features, because \fBcntlm\fP alone won't know your +the configuration file, you are bound to lose tunneling features, because \fBcntlm\fP alone won't know your credentials. Because NTLM identification has at least three parts (username, password, domain) and the basic authentication @@ -360,6 +360,17 @@ Workstation NetBIOS name. Do not use full qualified domain name (FQDN) here. Jus If not specified, \fBcntlm\fP tries to get the system hostname and if that fails, uses "cntlm" - it's because some proxies require this field non-empty. +.TP +.B -X +Use \fBSSPI\fP with specified handle type. Works only under Windows. Default is negotiate. + +.TP +.B -Z +Requires the \fB-p\fP option. Use this option to get hashes for password-less configuration in JSON format. In this +mode, \fBcntlm\fP prints the results and exits. You ought to use this option with explicit \fB-u\fP and \fB-d\fP, +because some hashes include the username and domain name in the calculation. Do see \fB-a\fP for security +recommendations. + .SH CONFIGURATION Configuration file is basically an INI file, except there are no "=" between keys and values. It comprises of whitespace delimited keyword and value pairs. Apart from that, there are sections as well, they have the usual diff --git a/main.c b/main.c index ce7650ea..99dfa851 100644 --- a/main.c +++ b/main.c @@ -689,6 +689,7 @@ int main(int argc, char **argv) { int tracefile = 0; int cflags = 0; int asdaemon = 1; + int apihash = 0; char *myconfig = NULL; plist_t tunneld_list = NULL; plist_t proxyd_list = NULL; @@ -717,7 +718,7 @@ int main(int argc, char **argv) { syslog(LOG_INFO, "Starting cntlm version " VERSION " for LITTLE endian\n"); #endif - while ((i = getopt(argc, argv, ":-:T:a:c:d:fghIl:p:r:su:vw:A:BD:F:G:HL:M:N:O:P:R:S:U:X:")) != -1) { + while ((i = getopt(argc, argv, ":-:T:a:c:d:fghIl:p:r:su:vw:A:BD:F:G:HL:M:N:O:P:R:S:U:X:Z")) != -1) { switch (i) { case 'A': case 'D': @@ -870,6 +871,9 @@ int main(int argc, char **argv) { help = 1; #endif break; + case 'Z': + apihash = 1; + break; case 'h': default: help = 1; @@ -887,7 +891,7 @@ int main(int argc, char **argv) { "newer. For more information about these matters, see the file LICENSE.\n" "For copyright holders of included encryption routines see headers.\n\n"); - fprintf(stderr, "Usage: %s [-AaBcDdFfgHhILlMPpSsTUuvw] [:] ...\n", argv[0]); + fprintf(stderr, "Usage: %s [-AaBcDdFfgHhILlMPpSsTUuvwXZ] [:] ...\n", argv[0]); fprintf(stderr, "\t-A
[/]\n" "\t ACL allow rule. IP or hostname, net must be a number (CIDR notation)\n"); fprintf(stderr, "\t-a ntlm | nt | lm\n" @@ -944,7 +948,8 @@ int main(int argc, char **argv) { "\t Some proxies require correct NetBIOS hostname.\n"); fprintf(stderr, "\t-X \n" "\t Use SSPI with specified handle type. Works only under Windows.\n" - "\t Default is negotiate.\n\n"); + "\t Default is negotiate.\n"); + fprintf(stderr, "\t-Z Generate JSON password hashes for use in APIs (requires -p flag).\n\n"); exit(1); } @@ -1185,10 +1190,10 @@ int main(int argc, char **argv) { config_close(cf); - if (!interactivehash && !parent_list) + if (!interactivehash && !parent_list && !apihash) croak("Parent proxy address missing.\n", interactivepwd || magic_detect); - if (!interactivehash && !magic_detect && !proxyd_list) + if (!interactivehash && !magic_detect && !proxyd_list && !apihash) croak("No proxy service ports were successfully opened.\n", interactivepwd); /* @@ -1266,6 +1271,13 @@ int main(int argc, char **argv) { printf("\n"); } + if (apihash) { + if (strlen(cpassword) == 0) { + printf("Use '-p' flag to provide a password!\n"); + goto bailout; + } + } + /* * Convert optional PassNT, PassLM and PassNTLMv2 strings to hashes * unless plaintext pass was used, which has higher priority. @@ -1302,15 +1314,15 @@ int main(int argc, char **argv) { free(tmp); } } else { - if (g_creds->hashnt || magic_detect || interactivehash) { + if (g_creds->hashnt || magic_detect || interactivehash || apihash) { tmp = ntlm_hash_nt_password(cpassword); auth_memcpy(g_creds, passnt, tmp, 21); free(tmp); - } if (g_creds->hashlm || magic_detect || interactivehash) { + } if (g_creds->hashlm || magic_detect || interactivehash || apihash) { tmp = ntlm_hash_lm_password(cpassword); auth_memcpy(g_creds, passlm, tmp, 21); free(tmp); - } if (g_creds->hashntlm2 || magic_detect || interactivehash) { + } if (g_creds->hashntlm2 || magic_detect || interactivehash || apihash) { tmp = ntlm2_hash_password(cuser, cdomain, cpassword); auth_memcpy(g_creds, passntlm2, tmp, 16); free(tmp); @@ -1362,6 +1374,32 @@ int main(int argc, char **argv) { goto bailout; } + if (apihash) { + printf("["); + if (g_creds->passlm) { + tmp = printmem(g_creds->passlm, 16, 8); + printf("{\"PassLM\" : {\"hash\" : \"%s\"}}", tmp); + free(tmp); + } + + if (g_creds->passnt) { + if (g_creds -> passlm) { printf(","); } + tmp = printmem(g_creds->passnt, 16, 8); + printf("{\"PassNT\" : {\"hash\" : \"%s\"}}", tmp); + free(tmp); + } + + if (g_creds->passntlm2) { + if (g_creds -> passlm || g_creds -> passnt) { printf(","); } + tmp = printmem(g_creds->passntlm2, 16, 8); + printf("{\"PassNTLMv2\" : { \"hash\":\"%s\", \"user\":\"%s\", \"domain\":\"%s\" }}", + tmp, g_creds->user, g_creds->domain); + free(tmp); + } + printf("]\n"); + goto bailout; + } + /* * If we're going to need a password, check we really have it. */