2 * This is the main module of the CNTLM
4 * CNTLM is free software; you can redistribute it and/or modify it under the
5 * terms of the GNU General Public License as published by the Free Software
6 * Foundation; either version 2 of the License, or (at your option) any later
9 * CNTLM is distributed in the hope that it will be useful, but WITHOUT ANY
10 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
16 * St, Fifth Floor, Boston, MA 02110-1301, USA.
18 * Copyright (c) 2007 David Kubicek
22 #include <sys/types.h>
24 #include <sys/select.h>
26 #include <sys/socket.h>
30 #include <netinet/in.h>
31 #include <arpa/inet.h>
46 * Some helping routines like linked list manipulation substr(), memory
47 * allocation, NTLM authentication routines, etc.
49 #include "config/config.h"
60 #include "forward.h" /* code serving via parent proxy */
61 #include "direct.h" /* code serving directly without proxy */
63 #define STACK_SIZE sizeof(void *)*8*1024
66 * Global "read-only" data initialized in main(). Comments list funcs. which use
67 * them. Having these global avoids the need to pass them to each thread and
68 * from there again a few times to inner calls.
70 int debug
= 0; /* all debug printf's and possibly external modules */
72 struct auth_s
*g_creds
= NULL
; /* throughout the whole module */
74 int quit
= 0; /* sighandler() */
75 int ntlmbasic
= 0; /* forward_request() */
77 int scanner_plugin
= 0;
78 long scanner_plugin_maxsize
= 0;
81 * List of finished threads. Each forward_request() thread adds itself to it when
82 * finished. Main regularly joins and removes all tid's in there.
84 plist_t threads_list
= NULL
;
85 pthread_mutex_t threads_mtx
= PTHREAD_MUTEX_INITIALIZER
;
88 * List of cached connections. Accessed by each thread forward_request().
90 plist_t connection_list
= NULL
;
91 pthread_mutex_t connection_mtx
= PTHREAD_MUTEX_INITIALIZER
;
94 * List of available proxies and current proxy id for proxy_connect().
97 plist_t parent_list
= NULL
;
100 * List of custom header substitutions, SOCKS5 proxy users and
101 * UserAgents for the scanner plugin.
103 hlist_t header_list
= NULL
; /* forward_request() */
104 hlist_t users_list
= NULL
; /* socks5_thread() */
105 plist_t scanner_agent_list
= NULL
; /* scanner_hook() */
106 plist_t noproxy_list
= NULL
; /* proxy_thread() */
109 * General signal handler. If in debug mode, quit immediately.
111 void sighandler(int p
) {
113 syslog(LOG_INFO
, "Signal %d received, issuing clean shutdown\n", p
);
115 syslog(LOG_INFO
, "Signal %d received, forcing shutdown\n", p
);
122 * Parse proxy parameter and add it to the global list.
124 int parent_add(char *parent
, int port
) {
130 * Check format and parse it.
132 proxy
= strdup(parent
);
134 i
= strcspn(proxy
, ": ");
137 while (i
< len
&& (proxy
[i
] == ' ' || proxy
[i
] == '\t'))
145 port
= atoi(proxy
+i
);
149 * No port argument and not parsed from proxy?
152 syslog(LOG_ERR
, "Invalid proxy specification %s.\n", parent
);
158 * Try to resolve proxy address
161 syslog(LOG_INFO, "Resolving proxy %s...\n", proxy);
162 if (!so_resolv(&host, proxy)) {
163 syslog(LOG_ERR, "Cannot resolve proxy %s, discarding.\n", parent);
169 aux
= (proxy_t
*)new(sizeof(proxy_t
));
170 strlcpy(aux
->hostname
, proxy
, sizeof(aux
->hostname
));
173 parent_list
= plist_add(parent_list
, ++parent_count
, (char *)aux
);
180 * Register and bind new proxy service port.
182 void listen_add(const char *service
, plist_t
*list
, char *spec
, int gateway
) {
183 struct in_addr source
;
188 p
= strcspn(spec
, ":");
190 tmp
= substr(spec
, 0, p
);
191 if (!so_resolv(&source
, tmp
)) {
192 syslog(LOG_ERR
, "Cannot resolve listen address %s\n", tmp
);
196 port
= atoi(tmp
= spec
+p
+1);
198 source
.s_addr
= htonl(gateway
? INADDR_ANY
: INADDR_LOOPBACK
);
199 port
= atoi(tmp
= spec
);
203 syslog(LOG_ERR
, "Invalid listen port %s.\n", tmp
);
207 i
= so_listen(port
, source
);
209 *list
= plist_add(*list
, i
, NULL
);
210 syslog(LOG_INFO
, "%s listening on %s:%d\n", service
, inet_ntoa(source
), port
);
215 * Register a new tunnel definition, bind service port.
217 void tunnel_add(plist_t
*list
, char *spec
, int gateway
) {
218 struct in_addr source
;
219 int i
, len
, count
, pos
, port
;
226 for (count
= 1, i
= 0; count
< 4 && i
< len
; ++i
)
227 if (spec
[i
] == ':') {
229 field
[count
++] = spec
+i
+1;
234 if (!so_resolv(&source
, field
[pos
])) {
235 syslog(LOG_ERR
, "Cannot resolve tunel bind address: %s\n", field
[pos
]);
240 source
.s_addr
= htonl(gateway
? INADDR_ANY
: INADDR_LOOPBACK
);
242 if (count
-pos
== 3) {
243 port
= atoi(field
[pos
]);
245 syslog(LOG_ERR
, "Invalid tunnel local port: %s\n", field
[pos
]);
249 if (!strlen(field
[pos
+1]) || !strlen(field
[pos
+2])) {
250 syslog(LOG_ERR
, "Invalid tunnel target: %s:%s\n", field
[pos
+1], field
[pos
+2]);
254 tmp
= new(strlen(field
[pos
+1]) + strlen(field
[pos
+2]) + 2 + 1);
255 strcpy(tmp
, field
[pos
+1]);
257 strcat(tmp
, field
[pos
+2]);
259 i
= so_listen(port
, source
);
261 *list
= plist_add(*list
, i
, tmp
);
262 syslog(LOG_INFO
, "New tunnel from %s:%d to %s\n", inet_ntoa(source
), port
, tmp
);
266 printf("Tunnel specification incorrect ([laddress:]lport:rserver:rport).\n");
274 * Add no-proxy hostname/IP
276 plist_t
noproxy_add(plist_t list
, char *spec
) {
279 tok
= strtok_r(spec
, ", ", &save
);
280 while ( tok
!= NULL
) {
282 printf("Adding no-proxy for: '%s'\n", tok
);
283 list
= plist_add(list
, 0, strdup(tok
));
284 tok
= strtok_r(NULL
, ", ", &save
);
290 int noproxy_match(const char *addr
) {
295 if (list
->aux
&& strlen(list
->aux
)
296 && fnmatch(list
->aux
, addr
, 0) == 0) {
298 printf("MATCH: %s (%s)\n", addr
, (char *)list
->aux
);
301 printf(" NO: %s (%s)\n", addr
, (char *)list
->aux
);
310 * Proxy thread - decide between direct and forward based on NoProxy
312 void *proxy_thread(void *thread_data
) {
313 rr_data_t request
, ret
;
314 int keep_alive
; /* Proxy-Connection */
316 int cd
= ((struct thread_arg_s
*)thread_data
)->fd
;
323 printf("\n******* Round 1 C: %d *******\n", cd
);
324 printf("Reading headers (%d)...\n", cd
);
327 request
= new_rr_data();
328 if (!headers_recv(cd
, request
)) {
329 free_rr_data(request
);
335 * Are we being returned a request by forward_request or direct_request?
338 free_rr_data(request
);
342 keep_alive
= hlist_subcmp(request
->headers
, "Proxy-Connection", "keep-alive");
344 if (noproxy_match(request
->hostname
))
345 ret
= direct_request(thread_data
, request
);
347 ret
= forward_request(thread_data
, request
);
350 printf("proxy_thread: request rc = %p\n", (void *)ret
);
351 } while (ret
!= NULL
&& ret
!= (void *)-1);
353 free_rr_data(request
);
355 * If client asked for proxy keep-alive, loop unless the last server response
356 * requested (Proxy-)Connection: close.
358 } while (keep_alive
&& ret
!= (void *)-1 && !serialize
);
361 * Add ourselves to the "threads to join" list.
364 pthread_mutex_lock(&threads_mtx
);
365 threads_list
= plist_add(threads_list
, (unsigned long)pthread_self(), NULL
);
366 pthread_mutex_unlock(&threads_mtx
);
376 * Tunnel/port forward thread - this method is obviously better solution than using extra
377 * tools like "corkscrew" which after all require us for authentication and tunneling
378 * their HTTP CONNECT in the first place.
380 void *tunnel_thread(void *thread_data
) {
381 char *hostname
, *pos
;
382 char *thost
= ((struct thread_arg_s
*)thread_data
)->target
;
384 hostname
= strdup(thost
);
385 if ((pos
= strchr(hostname
, ':')) != NULL
)
388 if (noproxy_match(hostname
))
389 direct_tunnel(thread_data
);
391 forward_tunnel(thread_data
);
397 * Add ourself to the "threads to join" list.
399 pthread_mutex_lock(&threads_mtx
);
400 threads_list
= plist_add(threads_list
, (unsigned long)pthread_self(), NULL
);
401 pthread_mutex_unlock(&threads_mtx
);
409 void *socks5_thread(void *thread_data
) {
410 char *tmp
, *thost
, *tport
, *uname
, *upass
;
414 struct auth_s
*tcreds
= NULL
;
415 unsigned char *bs
= NULL
, *auths
= NULL
, *addr
= NULL
;
418 int open
= !hlist_count(users_list
);
420 int cd
= ((struct thread_arg_s
*)thread_data
)->fd
;
421 struct sockaddr_in caddr
= ((struct thread_arg_s
*)thread_data
)->addr
;
425 * Check client's version, possibly fuck'em
427 bs
= (unsigned char *)new(10);
428 thost
= new(MINIBUF_SIZE
);
429 tport
= new(MINIBUF_SIZE
);
431 if (r
!= 2 || bs
[0] != 5)
435 * Read offered auth schemes
438 auths
= (unsigned char *)new(c
+1);
439 r
= read(cd
, auths
, c
);
444 * Are we wide open and client is OK with no auth?
447 for (i
= 0; i
< c
&& (auths
[i
] || (found
= 0)); ++i
);
451 * If not, accept plain auth if offered
454 for (i
= 0; i
< c
&& (auths
[i
] != 2 || !(found
= 2)); ++i
);
458 * If not open and no auth offered or open and auth requested, fuck'em
459 * and complete the handshake
464 w
= write(cd
, bs
, 2);
469 w
= write(cd
, bs
, 2);
473 * Plain auth negotiated?
477 * Check ver and read username len
482 bs
[1] = 0xFF; /* Unsuccessful (not supported) */
483 w
= write(cd
, bs
, 2);
489 * Read username and pass len
492 r
= read(cd
, uname
, c
+1);
505 r
= read(cd
, upass
, c
);
514 * Check credentials against the list
516 tmp
= hlist_get(users_list
, uname
);
517 if (!hlist_count(users_list
) || (tmp
&& !strcmp(tmp
, upass
))) {
519 bs
[1] = 0; /* Success */
522 bs
[1] = 0xFF; /* Failed */
528 w
= write(cd
, bs
, 2);
533 * Fuck'em if auth failed
547 * Is it connect for supported address type (IPv4 or DNS)? If not, fuck'em
549 if (bs
[1] != 1 || (bs
[3] != 1 && bs
[3] != 3)) {
551 bs
[1] = 2; /* Not allowed */
553 bs
[3] = 1; /* Dummy IPv4 */
555 w
= write(cd
, bs
, 10);
560 * Ok, it's connect to a domain or IP
561 * Let's read dest address
564 ver
= 1; /* IPv4, we know the length */
566 } else if (bs
[3] == 3) {
567 ver
= 2; /* FQDN, get string length */
574 addr
= (unsigned char *)new(c
+10 + 1);
575 r
= read(cd
, addr
, c
);
581 * Convert the address to character string
584 sprintf(thost
, "%d.%d.%d.%d", addr
[0], addr
[1], addr
[2], addr
[3]); /* It's in network byte order */
586 strlcpy(thost
, (char *)addr
, MINIBUF_SIZE
);
590 * Read port number and convert to host byte order int
592 r
= read(cd
, &port
, 2);
597 if (noproxy_match(thost
)) {
598 sd
= host_connect(thost
, ntohs(port
));
601 sprintf(tport
, "%d", ntohs(port
));
602 strlcat(thost
, ":", MINIBUF_SIZE
);
603 strlcat(thost
, tport
, MINIBUF_SIZE
);
606 sd
= proxy_connect(tcreds
);
608 i
= prepare_http_connect(sd
, tcreds
, thost
);
612 * Direct or proxy connect?
616 * Connect/tunnel failed, report
619 bs
[1] = 1; /* General failure */
621 bs
[3] = 1; /* Dummy IPv4 */
623 w
= write(cd
, bs
, 10);
630 bs
[1] = 0; /* Success */
632 bs
[3] = 1; /* Dummy IPv4 */
634 w
= write(cd
, bs
, 10);
637 syslog(LOG_DEBUG
, "%s SOCKS %s", inet_ntoa(caddr
.sin_addr
), thost
);
640 * Let's give them bi-directional connection they asked for
664 int main(int argc
, char **argv
) {
666 char *cpassword
, *cpassntlm2
, *cpassnt
, *cpasslm
;
667 char *cuser
, *cdomain
, *cworkstation
, *cuid
, *cpidfile
, *cauth
;
669 struct termios termold
, termnew
;
670 pthread_attr_t pattr
;
682 int interactivepwd
= 0;
683 int interactivehash
= 0;
687 plist_t tunneld_list
= NULL
;
688 plist_t proxyd_list
= NULL
;
689 plist_t socksd_list
= NULL
;
690 plist_t rules
= NULL
;
692 char *magic_detect
= NULL
;
694 g_creds
= new_auth();
695 cuser
= new(MINIBUF_SIZE
);
696 cdomain
= new(MINIBUF_SIZE
);
697 cpassword
= new(MINIBUF_SIZE
);
698 cpassntlm2
= new(MINIBUF_SIZE
);
699 cpassnt
= new(MINIBUF_SIZE
);
700 cpasslm
= new(MINIBUF_SIZE
);
701 cworkstation
= new(MINIBUF_SIZE
);
702 cpidfile
= new(MINIBUF_SIZE
);
703 cuid
= new(MINIBUF_SIZE
);
704 cauth
= new(MINIBUF_SIZE
);
706 openlog("cntlm", LOG_CONS
, LOG_DAEMON
);
708 #if config_endian == 0
709 syslog(LOG_INFO
, "Starting cntlm version " VERSION
" for BIG endian\n");
711 syslog(LOG_INFO
, "Starting cntlm version " VERSION
" for LITTLE endian\n");
714 while ((i
= getopt(argc
, argv
, ":-:a:c:d:fghIl:p:r:su:vw:A:BD:F:G:HL:M:N:O:P:R:S:T:U:")) != -1) {
718 if (!acl_add(&rules
, optarg
, (i
== 'A' ? ACL_ALLOW
: ACL_DENY
)))
722 strlcpy(cauth
, optarg
, MINIBUF_SIZE
);
728 if (!(cf
= config_open(optarg
))) {
729 syslog(LOG_ERR
, "Cannot access specified config file: %s\n", optarg
);
734 strlcpy(cdomain
, optarg
, MINIBUF_SIZE
);
737 cflags
= swap32(strtoul(optarg
, &tmp
, 0));
743 if (strlen(optarg
)) {
745 if (!scanner_plugin_maxsize
)
746 scanner_plugin_maxsize
= 1;
747 i
= strlen(optarg
) + 3;
749 snprintf(tmp
, i
, "*%s*", optarg
);
750 scanner_agent_list
= plist_add(scanner_agent_list
, 0, tmp
);
764 * Parse and validate the argument.
765 * Create a listening socket for tunneling.
767 tunnel_add(&tunneld_list
, optarg
, gateway
);
771 * Create a listening socket for proxy function.
773 listen_add("Proxy", &proxyd_list
, optarg
, gateway
);
776 magic_detect
= strdup(optarg
);
779 noproxy_list
= noproxy_add(noproxy_list
, tmp
=strdup(optarg
));
783 listen_add("SOCKS5 proxy", &socksd_list
, optarg
, gateway
);
786 strlcpy(cpidfile
, optarg
, MINIBUF_SIZE
);
790 * Overwrite the password parameter with '*'s to make it
791 * invisible in "ps", /proc, etc.
793 strlcpy(cpassword
, optarg
, MINIBUF_SIZE
);
794 for (i
= strlen(optarg
)-1; i
>= 0; --i
)
798 tmp
= strdup(optarg
);
799 head
= strchr(tmp
, ':');
801 fprintf(stderr
, "Invalid username:password format for -R: %s\n", tmp
);
804 users_list
= hlist_add(users_list
, tmp
, head
+1,
805 HLIST_ALLOC
, HLIST_ALLOC
);
809 if (is_http_header(optarg
))
810 header_list
= hlist_add(header_list
,
811 get_http_header_name(optarg
),
812 get_http_header_value(optarg
),
813 HLIST_NOALLOC
, HLIST_NOALLOC
);
817 scanner_plugin_maxsize
= atol(optarg
);
821 * Do not use threads - for debugging purposes only
826 tracefile
= open(optarg
, O_CREAT
| O_TRUNC
| O_WRONLY
, 0600);
828 fprintf(stderr
, "Cannot create trace file.\n");
831 printf("Redirecting all output to %s\n", optarg
);
834 printf("Cntlm debug trace, version " VERSION
);
836 printf(" windows/cygwin port");
838 printf(".\nCommand line: ");
839 for (i
= 0; i
< argc
; ++i
)
840 printf("%s ", argv
[i
]);
845 strlcpy(cuid
, optarg
, MINIBUF_SIZE
);
848 i
= strcspn(optarg
, "@");
849 if (i
!= strlen(optarg
)) {
850 strlcpy(cuser
, optarg
, MIN(MINIBUF_SIZE
, i
+1));
851 strlcpy(cdomain
, optarg
+i
+1, MINIBUF_SIZE
);
853 strlcpy(cuser
, optarg
, MINIBUF_SIZE
);
859 openlog("cntlm", LOG_CONS
| LOG_PERROR
, LOG_DAEMON
);
862 strlcpy(cworkstation
, optarg
, MINIBUF_SIZE
);
874 printf("CNTLM - Accelerating NTLM Authentication Proxy version " VERSION
"\n");
875 printf("Copyright (c) 2oo7-2o1o David Kubicek\n\n"
876 "This program comes with NO WARRANTY, to the extent permitted by law. You\n"
877 "may redistribute copies of it under the terms of the GNU GPL Version 2 or\n"
878 "newer. For more information about these matters, see the file LICENSE.\n"
879 "For copyright holders of included encryption routines see headers.\n\n");
881 fprintf(stderr
, "Usage: %s [-AaBcDdFfgHhILlMPpSsTUuvw] <proxy_host>[:]<proxy_port> ...\n", argv
[0]);
882 fprintf(stderr
, "\t-A <address>[/<net>]\n"
883 "\t ACL allow rule. IP or hostname, net must be a number (CIDR notation)\n");
884 fprintf(stderr
, "\t-a ntlm | nt | lm\n"
885 "\t Authentication type - combined NTLM, just LM, or just NT. Default NTLM.\n"
886 "\t It is the most versatile setting and likely to work for you.\n");
887 fprintf(stderr
, "\t-B Enable NTLM-to-basic authentication.\n");
888 fprintf(stderr
, "\t-c <config_file>\n"
889 "\t Configuration file. Other arguments can be used as well, overriding\n"
890 "\t config file settings.\n");
891 fprintf(stderr
, "\t-D <address>[/<net>]\n"
892 "\t ACL deny rule. Syntax same as -A.\n");
893 fprintf(stderr
, "\t-d <domain>\n"
894 "\t Domain/workgroup can be set separately.\n");
895 fprintf(stderr
, "\t-f Run in foreground, do not fork into daemon mode.\n");
896 fprintf(stderr
, "\t-F <flags>\n"
897 "\t NTLM authentication flags.\n");
898 fprintf(stderr
, "\t-G <pattern>\n"
899 "\t User-Agent matching for the trans-isa-scan plugin.\n");
900 fprintf(stderr
, "\t-g Gateway mode - listen on all interfaces, not only loopback.\n");
901 fprintf(stderr
, "\t-H Print password hashes for use in config file (NTLMv2 needs -u and -d).\n");
902 fprintf(stderr
, "\t-h Print this help info along with version number.\n");
903 fprintf(stderr
, "\t-I Prompt for the password interactively.\n");
904 fprintf(stderr
, "\t-L [<saddr>:]<lport>:<rhost>:<rport>\n"
905 "\t Forwarding/tunneling a la OpenSSH. Same syntax - listen on lport\n"
906 "\t and forward all connections through the proxy to rhost:rport.\n"
907 "\t Can be used for direct tunneling without corkscrew, etc.\n");
908 fprintf(stderr
, "\t-l [<saddr>:]<lport>\n"
909 "\t Main listening port for the NTLM proxy.\n");
910 fprintf(stderr
, "\t-M <testurl>\n"
911 "\t Magic autodetection of proxy's NTLM dialect.\n");
912 fprintf(stderr
, "\t-N \"<hostname_wildcard1>[, <hostname_wildcardN>\"\n"
913 "\t List of URL's to serve direcly as stand-alone proxy (e.g. '*.local')\n");
914 fprintf(stderr
, "\t-O [<saddr>:]<lport>\n"
915 "\t Enable SOCKS5 proxy on port lport (binding to address saddr)\n");
916 fprintf(stderr
, "\t-P <pidfile>\n"
917 "\t Create a PID file upon successful start.\n");
918 fprintf(stderr
, "\t-p <password>\n"
919 "\t Account password. Will not be visible in \"ps\", /proc, etc.\n");
920 fprintf(stderr
, "\t-r \"HeaderName: value\"\n"
921 "\t Add a header substitution. All such headers will be added/replaced\n"
922 "\t in the client's requests.\n");
923 fprintf(stderr
, "\t-S <size_in_kb>\n"
924 "\t Enable automation of GFI WebMonitor ISA scanner for files < size_in_kb.\n");
925 fprintf(stderr
, "\t-s Do not use threads, serialize all requests - for debugging only.\n");
926 fprintf(stderr
, "\t-U <uid>\n"
927 "\t Run as uid. It is an important security measure not to run as root.\n");
928 fprintf(stderr
, "\t-u <user>[@<domain]\n"
929 "\t Domain/workgroup can be set separately.\n");
930 fprintf(stderr
, "\t-v Print debugging information.\n");
931 fprintf(stderr
, "\t-w <workstation>\n"
932 "\t Some proxies require correct NetBIOS hostname.\n\n");
937 * More arguments on the command-line? Must be proxies.
941 tmp
= strchr(argv
[i
], ':');
942 parent_add(argv
[i
], !tmp
&& i
+1 < argc
? atoi(argv
[i
+1]) : 0);
947 * No configuration file yet? Load the default.
952 tmp
= getenv("PROGRAMFILES(X86)");
953 if (tmp
== NULL
|| strlen(tmp
) == 0)
954 tmp
= getenv("PROGRAMFILES");
956 tmp
= "C:\\Program Files";
958 head
= new(MINIBUF_SIZE
);
959 strlcpy(head
, tmp
, MINIBUF_SIZE
);
960 strlcat(head
, "\\Cntlm\\cntlm.ini", MINIBUF_SIZE
);
961 cf
= config_open(head
);
963 cf
= config_open(SYSCONFDIR
"/cntlm.conf");
967 printf("Default config file opened successfully\n");
969 syslog(LOG_ERR
, "Could not open default config file\n");
975 * If any configuration file was successfully opened, parse it.
979 * Check if gateway mode is requested before actually binding any ports.
981 tmp
= new(MINIBUF_SIZE
);
982 CFG_DEFAULT(cf
, "Gateway", tmp
, MINIBUF_SIZE
);
983 if (!strcasecmp("yes", tmp
))
988 * Check for NTLM-to-basic settings
990 tmp
= new(MINIBUF_SIZE
);
991 CFG_DEFAULT(cf
, "NTLMToBasic", tmp
, MINIBUF_SIZE
);
992 if (!strcasecmp("yes", tmp
))
997 * Setup the rest of tunnels.
999 while ((tmp
= config_pop(cf
, "Tunnel"))) {
1000 tunnel_add(&tunneld_list
, tmp
, gateway
);
1005 * Bind the rest of proxy service ports.
1007 while ((tmp
= config_pop(cf
, "Listen"))) {
1008 listen_add("Proxy", &proxyd_list
, tmp
, gateway
);
1013 * Bind the rest of SOCKS5 service ports.
1015 while ((tmp
= config_pop(cf
, "SOCKS5Proxy"))) {
1016 listen_add("SOCKS5 proxy", &socksd_list
, tmp
, gateway
);
1021 * Accept only headers not specified on the command line.
1022 * Command line has higher priority.
1024 while ((tmp
= config_pop(cf
, "Header"))) {
1025 if (is_http_header(tmp
)) {
1026 head
= get_http_header_name(tmp
);
1027 if (!hlist_in(header_list
, head
))
1028 header_list
= hlist_add(header_list
, head
, get_http_header_value(tmp
),
1029 HLIST_ALLOC
, HLIST_NOALLOC
);
1032 syslog(LOG_ERR
, "Invalid header format: %s\n", tmp
);
1038 * Add the rest of parent proxies.
1040 while ((tmp
= config_pop(cf
, "Proxy"))) {
1046 * No ACLs on the command line? Use config file.
1048 if (rules
== NULL
) {
1051 if (!(i
=strcasecmp("Allow", list
->key
)) || !strcasecmp("Deny", list
->key
))
1052 if (!acl_add(&rules
, list
->value
, i
? ACL_DENY
: ACL_ALLOW
))
1057 while ((tmp
= config_pop(cf
, "Allow")))
1059 while ((tmp
= config_pop(cf
, "Deny")))
1066 CFG_DEFAULT(cf
, "Auth", cauth
, MINIBUF_SIZE
);
1067 CFG_DEFAULT(cf
, "Domain", cdomain
, MINIBUF_SIZE
);
1068 CFG_DEFAULT(cf
, "Password", cpassword
, MINIBUF_SIZE
);
1069 CFG_DEFAULT(cf
, "PassNTLMv2", cpassntlm2
, MINIBUF_SIZE
);
1070 CFG_DEFAULT(cf
, "PassNT", cpassnt
, MINIBUF_SIZE
);
1071 CFG_DEFAULT(cf
, "PassLM", cpasslm
, MINIBUF_SIZE
);
1072 CFG_DEFAULT(cf
, "Username", cuser
, MINIBUF_SIZE
);
1073 CFG_DEFAULT(cf
, "Workstation", cworkstation
, MINIBUF_SIZE
);
1075 tmp
= new(MINIBUF_SIZE
);
1076 CFG_DEFAULT(cf
, "Flags", tmp
, MINIBUF_SIZE
);
1078 cflags
= swap32(strtoul(tmp
, NULL
, 0));
1081 tmp
= new(MINIBUF_SIZE
);
1082 CFG_DEFAULT(cf
, "ISAScannerSize", tmp
, MINIBUF_SIZE
);
1083 if (!scanner_plugin_maxsize
&& strlen(tmp
)) {
1085 scanner_plugin_maxsize
= atoi(tmp
);
1089 while ((tmp
= config_pop(cf
, "NoProxy"))) {
1091 noproxy_list
= noproxy_add(noproxy_list
, tmp
);
1096 while ((tmp
= config_pop(cf
, "SOCKS5Users"))) {
1097 head
= strchr(tmp
, ':');
1099 syslog(LOG_ERR
, "Invalid username:password format for SOCKS5User: %s\n", tmp
);
1102 users_list
= hlist_add(users_list
, tmp
, head
+1, HLIST_ALLOC
, HLIST_ALLOC
);
1108 * Add User-Agent matching patterns.
1110 while ((tmp
= config_pop(cf
, "ISAScannerAgent"))) {
1112 if (!scanner_plugin_maxsize
)
1113 scanner_plugin_maxsize
= 1;
1115 if ((i
= strlen(tmp
))) {
1117 snprintf(head
, i
+3, "*%s*", tmp
);
1118 scanner_agent_list
= plist_add(scanner_agent_list
, 0, head
);
1124 * Print out unused/unknown options.
1128 syslog(LOG_INFO
, "Ignoring config file option: %s\n", list
->key
);
1135 if (!interactivehash
&& !parent_list
)
1136 croak("Parent proxy address missing.\n", interactivepwd
|| magic_detect
);
1138 if (!interactivehash
&& !magic_detect
&& !proxyd_list
)
1139 croak("No proxy service ports were successfully opened.\n", interactivepwd
);
1142 * Set default value for the workstation. Hostname if possible.
1144 if (!strlen(cworkstation
)) {
1145 #if config_gethostname == 1
1146 gethostname(cworkstation
, MINIBUF_SIZE
);
1148 if (!strlen(cworkstation
))
1149 strlcpy(cworkstation
, "cntlm", MINIBUF_SIZE
);
1151 syslog(LOG_INFO
, "Workstation name used: %s\n", cworkstation
);
1155 * Parse selected NTLM hash combination.
1157 if (strlen(cauth
)) {
1158 if (!strcasecmp("ntlm", cauth
)) {
1159 g_creds
->hashnt
= 1;
1160 g_creds
->hashlm
= 1;
1161 g_creds
->hashntlm2
= 0;
1162 } else if (!strcasecmp("nt", cauth
)) {
1163 g_creds
->hashnt
= 1;
1164 g_creds
->hashlm
= 0;
1165 g_creds
->hashntlm2
= 0;
1166 } else if (!strcasecmp("lm", cauth
)) {
1167 g_creds
->hashnt
= 0;
1168 g_creds
->hashlm
= 1;
1169 g_creds
->hashntlm2
= 0;
1170 } else if (!strcasecmp("ntlmv2", cauth
)) {
1171 g_creds
->hashnt
= 0;
1172 g_creds
->hashlm
= 0;
1173 g_creds
->hashntlm2
= 1;
1174 } else if (!strcasecmp("ntlm2sr", cauth
)) {
1175 g_creds
->hashnt
= 2;
1176 g_creds
->hashlm
= 0;
1177 g_creds
->hashntlm2
= 0;
1179 syslog(LOG_ERR
, "Unknown NTLM auth combination.\n");
1184 if (socksd_list
&& !users_list
)
1185 syslog(LOG_WARNING
, "SOCKS5 proxy will NOT require any authentication\n");
1188 syslog(LOG_INFO
, "Using following NTLM hashes: NTLMv2(%d) NT(%d) LM(%d)\n",
1189 g_creds
->hashntlm2
, g_creds
->hashnt
, g_creds
->hashlm
);
1192 syslog(LOG_INFO
, "Using manual NTLM flags: 0x%X\n", swap32(cflags
));
1193 g_creds
->flags
= cflags
;
1197 * Last chance to get password from the user
1199 if (interactivehash
|| magic_detect
|| (interactivepwd
&& !ntlmbasic
)) {
1200 printf("Password: ");
1201 tcgetattr(0, &termold
);
1203 termnew
.c_lflag
&= ~(ISIG
| ECHO
);
1204 tcsetattr(0, TCSADRAIN
, &termnew
);
1205 tmp
= fgets(cpassword
, MINIBUF_SIZE
, stdin
);
1206 tcsetattr(0, TCSADRAIN
, &termold
);
1207 i
= strlen(cpassword
) - 1;
1208 if (cpassword
[i
] == '\n') {
1210 if (cpassword
[i
- 1] == '\r')
1211 cpassword
[i
- 1] = 0;
1217 * Convert optional PassNT, PassLM and PassNTLMv2 strings to hashes
1218 * unless plaintext pass was used, which has higher priority.
1220 * If plain password is present, calculate its NT and LM hashes
1221 * and remove it from the memory.
1223 if (!strlen(cpassword
)) {
1224 if (strlen(cpassntlm2
)) {
1225 tmp
= scanmem(cpassntlm2
, 8);
1227 syslog(LOG_ERR
, "Invalid PassNTLMv2 hash, terminating\n");
1230 auth_memcpy(g_creds
, passntlm2
, tmp
, 16);
1233 if (strlen(cpassnt
)) {
1234 tmp
= scanmem(cpassnt
, 8);
1236 syslog(LOG_ERR
, "Invalid PassNT hash, terminating\n");
1239 auth_memcpy(g_creds
, passnt
, tmp
, 16);
1242 if (strlen(cpasslm
)) {
1243 tmp
= scanmem(cpasslm
, 8);
1245 syslog(LOG_ERR
, "Invalid PassLM hash, terminating\n");
1248 auth_memcpy(g_creds
, passlm
, tmp
, 16);
1252 if (g_creds
->hashnt
|| magic_detect
|| interactivehash
) {
1253 tmp
= ntlm_hash_nt_password(cpassword
);
1254 auth_memcpy(g_creds
, passnt
, tmp
, 21);
1256 } if (g_creds
->hashlm
|| magic_detect
|| interactivehash
) {
1257 tmp
= ntlm_hash_lm_password(cpassword
);
1258 auth_memcpy(g_creds
, passlm
, tmp
, 21);
1260 } if (g_creds
->hashntlm2
|| magic_detect
|| interactivehash
) {
1261 tmp
= ntlm2_hash_password(cuser
, cdomain
, cpassword
);
1262 auth_memcpy(g_creds
, passntlm2
, tmp
, 16);
1265 memset(cpassword
, 0, strlen(cpassword
));
1268 auth_strcpy(g_creds
, user
, cuser
);
1269 auth_strcpy(g_creds
, domain
, cdomain
);
1270 auth_strcpy(g_creds
, workstation
, cworkstation
);
1282 * Try known NTLM auth combinations and print which ones work.
1283 * User can pick the best (most secure) one as his config.
1286 magic_auth_detect(magic_detect
);
1290 if (interactivehash
) {
1291 if (g_creds
->passlm
) {
1292 tmp
= printmem(g_creds
->passlm
, 16, 8);
1293 printf("PassLM %s\n", tmp
);
1297 if (g_creds
->passnt
) {
1298 tmp
= printmem(g_creds
->passnt
, 16, 8);
1299 printf("PassNT %s\n", tmp
);
1303 if (g_creds
->passntlm2
) {
1304 tmp
= printmem(g_creds
->passntlm2
, 16, 8);
1305 printf("PassNTLMv2 %s # Only for user '%s', domain '%s'\n",
1306 tmp
, g_creds
->user
, g_creds
->domain
);
1313 * If we're going to need a password, check we really have it.
1316 (g_creds
->hashnt
&& !g_creds
->passnt
)
1317 || (g_creds
->hashlm
&& !g_creds
->passlm
)
1318 || (g_creds
->hashntlm2
&& !g_creds
->passntlm2
))) {
1319 syslog(LOG_ERR
, "Parent proxy account password (or required hashes) missing.\n");
1324 * Ok, we are ready to rock. If daemon mode was requested,
1325 * fork and die. The child will not be group leader anymore
1326 * and can thus create a new session for itself and detach
1327 * from the controlling terminal.
1331 printf("Forking into background as requested.\n");
1335 perror("Fork into background failed"); /* fork failed */
1338 myexit(0); /* parent */
1343 i
= open("/dev/null", O_RDWR
);
1354 * Reinit syslog logging to include our PID, after forking
1355 * it is going to be OK
1358 openlog("cntlm", LOG_CONS
| LOG_PID
, LOG_DAEMON
);
1359 syslog(LOG_INFO
, "Daemon ready");
1361 openlog("cntlm", LOG_CONS
| LOG_PID
| LOG_PERROR
, LOG_DAEMON
);
1362 syslog(LOG_INFO
, "Cntlm ready, staying in the foreground");
1366 * Check and change UID.
1369 if (getuid() && geteuid()) {
1370 syslog(LOG_WARNING
, "No root privileges; keeping identity %d:%d\n", getuid(), getgid());
1372 if (isdigit(cuid
[0])) {
1376 syslog(LOG_ERR
, "Numerical uid parameter invalid\n");
1380 pw
= getpwnam(cuid
);
1381 if (!pw
|| !pw
->pw_uid
) {
1382 syslog(LOG_ERR
, "Username %s in -U is invalid\n", cuid
);
1390 syslog(LOG_INFO
, "Changing uid:gid to %d:%d - %s\n", nuid
, ngid
, strerror(errno
));
1392 syslog(LOG_ERR
, "Terminating\n");
1399 * PID file requested? Try to create one (it must not exist).
1400 * If we fail, exit with error.
1402 if (strlen(cpidfile
)) {
1404 cd
= open(cpidfile
, O_WRONLY
| O_CREAT
| O_TRUNC
, 0644);
1406 syslog(LOG_ERR
, "Error creating a new PID file\n");
1411 snprintf(tmp
, 50, "%d\n", getpid());
1412 w
= write(cd
, tmp
, strlen(tmp
));
1418 * Change the handler for signals recognized as clean shutdown.
1419 * When the handler is called (termination request), it signals
1420 * this news by adding 1 to the global quit variable.
1422 signal(SIGPIPE
, SIG_IGN
);
1423 signal(SIGINT
, &sighandler
);
1424 signal(SIGTERM
, &sighandler
);
1425 signal(SIGHUP
, &sighandler
);
1428 * Initialize the random number generator
1430 srandom(time(NULL
));
1433 * This loop iterates over every connection request on any of
1434 * the listening ports. We keep the number of created threads.
1436 * We also check the "finished threads" list, threads_list, here and
1437 * free the memory of all inactive threads. Then, we update the
1438 * number of finished threads.
1440 * The loop ends, when we were "killed" and all threads created
1441 * are finished, OR if we were killed more than once. This way,
1442 * we have a "clean" shutdown (wait for all connections to finish
1443 * after the first kill) and a "forced" one (user insists and
1446 while (quit
== 0 || (tc
!= tj
&& quit
< 2)) {
1447 struct thread_arg_s
*data
;
1448 struct sockaddr_in caddr
;
1458 * Watch for proxy ports.
1462 FD_SET(t
->key
, &set
);
1467 * Watch for SOCKS5 ports.
1471 FD_SET(t
->key
, &set
);
1476 * Watch for tunneled ports.
1480 FD_SET(t
->key
, &set
);
1488 * Wait here for data (connection request) on any of the listening
1489 * sockets. When ready, establish the connection. For the main
1490 * port, a new proxy_thread() thread is spawned to service the HTTP
1491 * request. For tunneled ports, tunnel_thread() thread is created
1492 * and for SOCKS port, socks5_thread() is created.
1494 * All threads are defined in forward.c, except for local proxy_thread()
1495 * which routes the request as forwarded or direct, depending on the
1496 * URL host name and NoProxy settings.
1498 cd
= select(FD_SETSIZE
, &set
, NULL
, NULL
, &tv
);
1500 for (i
= 0; i
< FD_SETSIZE
; ++i
) {
1501 if (!FD_ISSET(i
, &set
))
1504 clen
= sizeof(caddr
);
1505 cd
= accept(i
, (struct sockaddr
*)&caddr
, (socklen_t
*)&clen
);
1508 syslog(LOG_ERR
, "Serious error during accept: %s\n", strerror(errno
));
1513 * Check main access control list.
1515 if (acl_check(rules
, caddr
.sin_addr
) != ACL_ALLOW
) {
1516 syslog(LOG_WARNING
, "Connection denied for %s:%d\n",
1517 inet_ntoa(caddr
.sin_addr
), ntohs(caddr
.sin_port
));
1518 tmp
= gen_denied_page(inet_ntoa(caddr
.sin_addr
));
1519 w
= write(cd
, tmp
, strlen(tmp
));
1526 * Log peer IP if it's not localhost
1528 * if (debug || (gateway && caddr.sin_addr.s_addr != htonl(INADDR_LOOPBACK)))
1529 * syslog(LOG_INFO, "Connection accepted from %s:%d\n",
1530 * inet_ntoa(caddr.sin_addr), ntohs(caddr.sin_port));
1533 pthread_attr_init(&pattr
);
1534 pthread_attr_setstacksize(&pattr
, STACK_SIZE
);
1536 pthread_attr_setguardsize(&pattr
, 256);
1539 if (plist_in(proxyd_list
, i
)) {
1540 data
= (struct thread_arg_s
*)new(sizeof(struct thread_arg_s
));
1544 tid
= pthread_create(&pthr
, &pattr
, proxy_thread
, (void *)data
);
1546 proxy_thread((void *)data
);
1547 } else if (plist_in(socksd_list
, i
)) {
1548 data
= (struct thread_arg_s
*)new(sizeof(struct thread_arg_s
));
1551 tid
= pthread_create(&pthr
, &pattr
, socks5_thread
, (void *)data
);
1553 data
= (struct thread_arg_s
*)new(sizeof(struct thread_arg_s
));
1556 data
->target
= plist_get(tunneld_list
, i
);
1557 tid
= pthread_create(&pthr
, &pattr
, tunnel_thread
, (void *)data
);
1560 pthread_attr_destroy(&pattr
);
1563 syslog(LOG_ERR
, "Serious error during pthread_create: %d\n", tid
);
1567 } else if (cd
< 0 && !quit
)
1568 syslog(LOG_ERR
, "Serious error during select: %s\n", strerror(errno
));
1571 pthread_mutex_lock(&threads_mtx
);
1574 plist_t tmp
= t
->next
;
1575 tid
= pthread_join((pthread_t
)t
->key
, (void *)&i
);
1580 printf("Joining thread %lu; rc: %d\n", t
->key
, i
);
1582 syslog(LOG_ERR
, "Serious error during pthread_join: %d\n", tid
);
1587 threads_list
= NULL
;
1588 pthread_mutex_unlock(&threads_mtx
);
1593 if (strlen(cpidfile
))
1596 syslog(LOG_INFO
, "Terminating with %d active threads\n", tc
- tj
);
1597 pthread_mutex_lock(&connection_mtx
);
1598 plist_free(connection_list
);
1599 pthread_mutex_unlock(&connection_mtx
);
1601 hlist_free(header_list
);
1602 plist_free(scanner_agent_list
);
1603 plist_free(noproxy_list
);
1604 plist_free(tunneld_list
);
1605 plist_free(proxyd_list
);
1606 plist_free(socksd_list
);
1614 plist_free(parent_list
);