3232#include <errno.h>
3333#include <limits.h>
3434#include <assert.h>
35- #if !defined(STUBBY_ON_WINDOWS ) && !defined(GETDNS_ON_WINDOWS )
35+ #if defined(STUBBY_ON_WINDOWS ) || defined(GETDNS_ON_WINDOWS )
36+ #include <shlobj.h>
37+ #else
38+ #include <pwd.h>
3639#include <unistd.h>
3740#endif
3841#include <signal.h>
@@ -62,7 +65,17 @@ getdns_yaml2dict(const char *str, getdns_dict **dict)
6265}
6366#endif
6467
65- #define STUBBYPIDFILE RUNSTATEDIR"/stubby.pid"
68+ static char * make_config_file_path (const char * dir , const char * fname )
69+ {
70+ int reslen = strlen (dir ) + strlen (fname ) + 1 ;
71+ char * res = malloc (reslen );
72+
73+ if (res == NULL )
74+ return NULL ;
75+
76+ snprintf (res , reslen , "%s%s" , dir , fname );
77+ return res ;
78+ }
6679
6780#if defined(STUBBY_ON_WINDOWS ) || defined(GETDNS_ON_WINDOWS )
6881#define DEBUG_ON (...) do { \
@@ -78,7 +91,31 @@ getdns_yaml2dict(const char *str, getdns_dict **dict)
7891 fprintf(stderr, "[%s.%.6d] ", buf_dEbUgSyM, (int)tv_dEbUgSyM.tv_usec); \
7992 fprintf(stderr, __VA_ARGS__); \
8093 } while (0)
94+
95+ static char * folder_config_file (int csidl )
96+ {
97+ TCHAR szPath [MAX_PATH ];
98+
99+ if (!SUCCEEDED (SHGetFolderPath (NULL ,
100+ csidl | CSIDL_FLAG_CREATE , NULL , 0 , szPath )))
101+ return NULL ;
102+
103+ return make_config_file_path (szPath , "\\Stubby\\stubby.yml" );
104+ }
105+
106+ // %APPDATA%/Stubby/stubby.yml.
107+ char * home_config_file ()
108+ {
109+ return folder_config_file (CSIDL_APPDATA );
110+ }
111+
112+ char * system_config_file ()
113+ {
114+ return folder_config_file (CSIDL_PROGRAM_FILES );
115+ }
81116#else
117+ #define STUBBYPIDFILE RUNSTATEDIR"/stubby.pid"
118+
82119#define DEBUG_ON (...) do { \
83120 struct timeval tv_dEbUgSyM; \
84121 struct tm tm_dEbUgSyM; \
@@ -90,6 +127,20 @@ getdns_yaml2dict(const char *str, getdns_dict **dict)
90127 fprintf(stderr, "[%s.%.6d] ", buf_dEbUgSyM, (int)tv_dEbUgSyM.tv_usec); \
91128 fprintf(stderr, __VA_ARGS__); \
92129 } while (0)
130+
131+ char * home_config_file ()
132+ {
133+ struct passwd * p = getpwuid (getuid ());
134+ char * home = p ? p -> pw_dir : getenv ("HOME" );
135+ if (!home )
136+ return NULL ;
137+ return make_config_file_path (home , "/.stubby.yml" );
138+ }
139+
140+ char * system_config_file ()
141+ {
142+ return make_config_file_path (STUBBYCONFDIR , "/stubby.yml" );
143+ }
93144#endif
94145#define DEBUG_OFF (...) do {} while (0)
95146
@@ -126,6 +177,8 @@ static void stubby_local_log(void *userarg, uint64_t system,
126177void
127178print_usage (FILE * out )
128179{
180+ char * home_conf_fn = home_config_file ();
181+ char * system_conf_fn = system_config_file ();
129182 fprintf (out , "usage: " STUBBY_PACKAGE " [<option> ...] \\\n" );
130183 fprintf (out , "\t-C\t<filename>\n" );
131184 fprintf (out , "\t\tRead settings from config file <filename>\n" );
@@ -135,16 +188,16 @@ print_usage(FILE *out)
135188 fprintf (out , "\t\tspecified on the command line.)\n" );
136189 fprintf (out , "\t\tBy default, the configuration file location is obtained\n" );
137190 fprintf (out , "\t\tby looking for YAML files in the following order:\n" );
138- fprintf (out , "\t\t\t\"%s/.stubby.yml \"\n" , getenv ( "HOME" ) );
139- fprintf (out , "\t\t\t\"%s/stubby.yml \"\n" , STUBBYCONFDIR );
140- fprintf (out , "\t\tAn default file (Using Strict mode) is installed as\n" );
141- fprintf (out , "\t\t\t\"%s/stubby.yml \"\n" , STUBBYCONFDIR );
191+ fprintf (out , "\t\t\t\"%s\"\n" , home_conf_fn );
192+ fprintf (out , "\t\t\t\"%s\"\n" , system_conf_fn );
193+ fprintf (out , "\t\tA default file (Using Strict mode) is installed as\n" );
194+ fprintf (out , "\t\t\t\"%s\"\n" , system_conf_fn );
142195#if !defined(STUBBY_ON_WINDOWS ) && !defined(GETDNS_ON_WINDOWS )
143196 fprintf (out , "\t-g\tRun stubby in background (default is foreground)\n" );
144197#endif
145198 fprintf (out , "\t-h\tPrint this help\n" );
146199 fprintf (out , "\t-i\tValidate and print the configuration only. Useful to validate config file\n" );
147- fprintf (out , "\t\t\ tcontents. Note: does not attempt to bind to the listen addresses.\n" );
200+ fprintf (out , "\t\tcontents. Note: does not attempt to bind to the listen addresses.\n" );
148201 fprintf (out , "\t-l\tEnable logging of all logs (same as -v 7)\n" );
149202 fprintf (out , "\t-v\tSpecify logging level (overrides -l option). Values are\n" );
150203 fprintf (out , "\t\t\t0: EMERG - %s\n" , GETDNS_LOG_EMERG_TEXT );
@@ -156,6 +209,8 @@ print_usage(FILE *out)
156209 fprintf (out , "\t\t\t6: INFO - %s\n" , GETDNS_LOG_INFO_TEXT );
157210 fprintf (out , "\t\t\t7: DEBUG - %s\n" , GETDNS_LOG_DEBUG_TEXT );
158211 fprintf (out , "\t-V\tPrint the " STUBBY_PACKAGE " version\n" );
212+ free (home_conf_fn );
213+ free (system_conf_fn );
159214}
160215
161216void
@@ -702,9 +757,9 @@ void stubby_local_log(void *userarg, uint64_t system,
702757int
703758main (int argc , char * * argv )
704759{
705- char home_stubby_conf_fn_spc [ 1024 ], * home_stubby_conf_fn = NULL ;
760+ char * conf_fn ;
706761 const char * custom_config_fn = NULL ;
707- int fn_sz ;
762+ int found_conf = 0 ;
708763 int print_api_info = 0 ;
709764 int log_connections = 0 ;
710765 getdns_return_t r ;
@@ -771,48 +826,36 @@ main(int argc, char **argv)
771826 return r ;
772827 }
773828 } else {
774- fn_sz = snprintf ( home_stubby_conf_fn_spc
775- , sizeof (home_stubby_conf_fn_spc )
776- , "%s/.stubby.yml"
777- , getenv ("HOME" )
778- );
779-
780- if (fn_sz > 0 && fn_sz < (int )sizeof (home_stubby_conf_fn_spc ))
781- home_stubby_conf_fn = home_stubby_conf_fn_spc ;
782-
783- else if (fn_sz > 0 ) {
784- if (!(home_stubby_conf_fn = malloc (fn_sz + 1 )) ||
785- snprintf ( home_stubby_conf_fn , fn_sz
786- , "%s/.stubby.yml" , getenv ("HOME" )) != fn_sz ) {
787- if (home_stubby_conf_fn ) {
788- free (home_stubby_conf_fn );
789- home_stubby_conf_fn = NULL ;
790- }
791- }
829+ conf_fn = home_config_file ();
830+ if (!conf_fn ) {
831+ fprintf (stderr , "Error getting user config file" );
832+ exit (EXIT_FAILURE );
792833 }
793- if (home_stubby_conf_fn &&
794- (r = parse_config_file (home_stubby_conf_fn ))) {
795- if (r != GETDNS_RETURN_IO_ERROR )
834+ r = parse_config_file (conf_fn );
835+ if (r == GETDNS_RETURN_GOOD )
836+ found_conf = 1 ;
837+ else if (r != GETDNS_RETURN_IO_ERROR )
838+ fprintf ( stderr , "Error parsing config file "
839+ "\"%s\": %s\n" , conf_fn
840+ , _getdns_strerror (r ));
841+ free (conf_fn );
842+ if (!found_conf ) {
843+ conf_fn = system_config_file ();
844+ if (!conf_fn ) {
845+ fprintf (stderr , "Error getting system config file" );
846+ exit (EXIT_FAILURE );
847+ }
848+ r = parse_config_file (conf_fn );
849+ if (r == GETDNS_RETURN_GOOD )
850+ found_conf = 1 ;
851+ else if (r != GETDNS_RETURN_IO_ERROR )
796852 fprintf ( stderr , "Error parsing config file "
797- "\"%s\": %s\n" , home_stubby_conf_fn
853+ "\"%s\": %s\n" , conf_fn
798854 , _getdns_strerror (r ));
799- if (home_stubby_conf_fn != home_stubby_conf_fn_spc )
800- free (home_stubby_conf_fn );
801- home_stubby_conf_fn = NULL ;
855+ free (conf_fn );
802856 }
803- if (!home_stubby_conf_fn &&
804- (r = parse_config_file (STUBBYCONFDIR "/stubby.yml" ))) {
805- if (r != GETDNS_RETURN_IO_ERROR ) {
806- fprintf ( stderr , "Error parsing config file \"%s\": %s\n"
807- , STUBBYCONFDIR "/stubby.yml"
808- , _getdns_strerror (r ));
809- }
857+ if (!found_conf )
810858 fprintf (stderr , "WARNING: No Stubby config file found... using minimal default config (Opportunistic Usage)\n" );
811- }
812- if (home_stubby_conf_fn &&
813- home_stubby_conf_fn != home_stubby_conf_fn_spc ) {
814- free (home_stubby_conf_fn );
815- }
816859 }
817860 if ((r = getdns_context_set_resolution_type (context , GETDNS_RESOLUTION_STUB ))) {
818861 fprintf ( stderr , "Error while trying to configure stubby for "
0 commit comments