1 /*
2  * Copyright (C) the libgit2 contributors. All rights reserved.
3  *
4  * This file is part of libgit2, distributed under the GNU GPL v2 with
5  * a Linking Exception. For full terms see the included COPYING file.
6  */
7 
8 #include "libgit2.h"
9 
10 #include <git2.h>
11 #include "alloc.h"
12 #include "cache.h"
13 #include "common.h"
14 #include "filter.h"
15 #include "hash.h"
16 #include "index.h"
17 #include "merge_driver.h"
18 #include "pool.h"
19 #include "mwindow.h"
20 #include "object.h"
21 #include "odb.h"
22 #include "refs.h"
23 #include "runtime.h"
24 #include "sysdir.h"
25 #include "thread.h"
26 #include "threadstate.h"
27 #include "git2/global.h"
28 #include "streams/registry.h"
29 #include "streams/mbedtls.h"
30 #include "streams/openssl.h"
31 #include "transports/smart.h"
32 #include "transports/http.h"
33 #include "transports/ssh.h"
34 
35 #ifdef GIT_WIN32
36 # include "win32/w32_leakcheck.h"
37 #endif
38 
39 #ifdef GIT_OPENSSL
40 # include <openssl/err.h>
41 #endif
42 
43 #ifdef GIT_MBEDTLS
44 # include <mbedtls/error.h>
45 #endif
46 
47 /* Declarations for tuneable settings */
48 extern size_t git_mwindow__window_size;
49 extern size_t git_mwindow__mapped_limit;
50 extern size_t git_mwindow__file_limit;
51 extern size_t git_indexer__max_objects;
52 extern bool git_disable_pack_keep_file_checks;
53 
54 char *git__user_agent;
55 char *git__ssl_ciphers;
56 
libgit2_settings_global_shutdown(void)57 static void libgit2_settings_global_shutdown(void)
58 {
59 	git__free(git__user_agent);
60 	git__free(git__ssl_ciphers);
61 }
62 
git_libgit2_settings_global_init(void)63 static int git_libgit2_settings_global_init(void)
64 {
65 	return git_runtime_shutdown_register(libgit2_settings_global_shutdown);
66 }
67 
git_libgit2_init(void)68 int git_libgit2_init(void)
69 {
70 	static git_runtime_init_fn init_fns[] = {
71 #ifdef GIT_WIN32
72 		git_win32_leakcheck_global_init,
73 #endif
74 		git_allocator_global_init,
75 		git_threadstate_global_init,
76 		git_threads_global_init,
77 		git_hash_global_init,
78 		git_sysdir_global_init,
79 		git_filter_global_init,
80 		git_merge_driver_global_init,
81 		git_transport_ssh_global_init,
82 		git_stream_registry_global_init,
83 		git_openssl_stream_global_init,
84 		git_mbedtls_stream_global_init,
85 		git_mwindow_global_init,
86 		git_pool_global_init,
87 		git_libgit2_settings_global_init
88 	};
89 
90 	return git_runtime_init(init_fns, ARRAY_SIZE(init_fns));
91 }
92 
git_libgit2_init_count(void)93 int git_libgit2_init_count(void)
94 {
95 	return git_runtime_init_count();
96 }
97 
git_libgit2_shutdown(void)98 int git_libgit2_shutdown(void)
99 {
100 	return git_runtime_shutdown();
101 }
102 
git_libgit2_version(int * major,int * minor,int * rev)103 int git_libgit2_version(int *major, int *minor, int *rev)
104 {
105 	*major = LIBGIT2_VER_MAJOR;
106 	*minor = LIBGIT2_VER_MINOR;
107 	*rev = LIBGIT2_VER_REVISION;
108 
109 	return 0;
110 }
111 
git_libgit2_features(void)112 int git_libgit2_features(void)
113 {
114 	return 0
115 #ifdef GIT_THREADS
116 		| GIT_FEATURE_THREADS
117 #endif
118 #ifdef GIT_HTTPS
119 		| GIT_FEATURE_HTTPS
120 #endif
121 #if defined(GIT_SSH)
122 		| GIT_FEATURE_SSH
123 #endif
124 #if defined(GIT_USE_NSEC)
125 		| GIT_FEATURE_NSEC
126 #endif
127 	;
128 }
129 
config_level_to_sysdir(int * out,int config_level)130 static int config_level_to_sysdir(int *out, int config_level)
131 {
132 	switch (config_level) {
133 	case GIT_CONFIG_LEVEL_SYSTEM:
134 		*out = GIT_SYSDIR_SYSTEM;
135 		return 0;
136 	case GIT_CONFIG_LEVEL_XDG:
137 		*out = GIT_SYSDIR_XDG;
138 		return 0;
139 	case GIT_CONFIG_LEVEL_GLOBAL:
140 		*out = GIT_SYSDIR_GLOBAL;
141 		return 0;
142 	case GIT_CONFIG_LEVEL_PROGRAMDATA:
143 		*out = GIT_SYSDIR_PROGRAMDATA;
144 		return 0;
145 	default:
146 		break;
147 	}
148 
149 	git_error_set(
150 		GIT_ERROR_INVALID, "invalid config path selector %d", config_level);
151 	return -1;
152 }
153 
git_libgit2__user_agent(void)154 const char *git_libgit2__user_agent(void)
155 {
156 	return git__user_agent;
157 }
158 
git_libgit2__ssl_ciphers(void)159 const char *git_libgit2__ssl_ciphers(void)
160 {
161 	return git__ssl_ciphers;
162 }
163 
git_libgit2_opts(int key,...)164 int git_libgit2_opts(int key, ...)
165 {
166 	int error = 0;
167 	va_list ap;
168 
169 	va_start(ap, key);
170 
171 	switch (key) {
172 	case GIT_OPT_SET_MWINDOW_SIZE:
173 		git_mwindow__window_size = va_arg(ap, size_t);
174 		break;
175 
176 	case GIT_OPT_GET_MWINDOW_SIZE:
177 		*(va_arg(ap, size_t *)) = git_mwindow__window_size;
178 		break;
179 
180 	case GIT_OPT_SET_MWINDOW_MAPPED_LIMIT:
181 		git_mwindow__mapped_limit = va_arg(ap, size_t);
182 		break;
183 
184 	case GIT_OPT_GET_MWINDOW_MAPPED_LIMIT:
185 		*(va_arg(ap, size_t *)) = git_mwindow__mapped_limit;
186 		break;
187 
188 	case GIT_OPT_SET_MWINDOW_FILE_LIMIT:
189 		git_mwindow__file_limit = va_arg(ap, size_t);
190 		break;
191 
192 	case GIT_OPT_GET_MWINDOW_FILE_LIMIT:
193 		*(va_arg(ap, size_t *)) = git_mwindow__file_limit;
194 		break;
195 
196 	case GIT_OPT_GET_SEARCH_PATH:
197 		{
198 			int sysdir = va_arg(ap, int);
199 			git_buf *out = va_arg(ap, git_buf *);
200 			const git_buf *tmp;
201 			int level;
202 
203 			if ((error = config_level_to_sysdir(&level, sysdir)) < 0 ||
204 			    (error = git_buf_sanitize(out)) < 0 ||
205 			    (error = git_sysdir_get(&tmp, level)) < 0)
206 				break;
207 
208 			error = git_buf_sets(out, tmp->ptr);
209 		}
210 		break;
211 
212 	case GIT_OPT_SET_SEARCH_PATH:
213 		{
214 			int level;
215 
216 			if ((error = config_level_to_sysdir(&level, va_arg(ap, int))) >= 0)
217 				error = git_sysdir_set(level, va_arg(ap, const char *));
218 		}
219 		break;
220 
221 	case GIT_OPT_SET_CACHE_OBJECT_LIMIT:
222 		{
223 			git_object_t type = (git_object_t)va_arg(ap, int);
224 			size_t size = va_arg(ap, size_t);
225 			error = git_cache_set_max_object_size(type, size);
226 			break;
227 		}
228 
229 	case GIT_OPT_SET_CACHE_MAX_SIZE:
230 		git_cache__max_storage = va_arg(ap, ssize_t);
231 		break;
232 
233 	case GIT_OPT_ENABLE_CACHING:
234 		git_cache__enabled = (va_arg(ap, int) != 0);
235 		break;
236 
237 	case GIT_OPT_GET_CACHED_MEMORY:
238 		*(va_arg(ap, ssize_t *)) = git_cache__current_storage.val;
239 		*(va_arg(ap, ssize_t *)) = git_cache__max_storage;
240 		break;
241 
242 	case GIT_OPT_GET_TEMPLATE_PATH:
243 		{
244 			git_buf *out = va_arg(ap, git_buf *);
245 			const git_buf *tmp;
246 
247 			if ((error = git_buf_sanitize(out)) < 0 ||
248 			    (error = git_sysdir_get(&tmp, GIT_SYSDIR_TEMPLATE)) < 0)
249 				break;
250 
251 			error = git_buf_sets(out, tmp->ptr);
252 		}
253 		break;
254 
255 	case GIT_OPT_SET_TEMPLATE_PATH:
256 		error = git_sysdir_set(GIT_SYSDIR_TEMPLATE, va_arg(ap, const char *));
257 		break;
258 
259 	case GIT_OPT_SET_SSL_CERT_LOCATIONS:
260 #ifdef GIT_OPENSSL
261 		{
262 			const char *file = va_arg(ap, const char *);
263 			const char *path = va_arg(ap, const char *);
264 			error = git_openssl__set_cert_location(file, path);
265 		}
266 #elif defined(GIT_MBEDTLS)
267 		{
268 			const char *file = va_arg(ap, const char *);
269 			const char *path = va_arg(ap, const char *);
270 			if (file)
271 				error = git_mbedtls__set_cert_location(file, 0);
272 			if (error && path)
273 				error = git_mbedtls__set_cert_location(path, 1);
274 		}
275 #else
276 		git_error_set(GIT_ERROR_SSL, "TLS backend doesn't support certificate locations");
277 		error = -1;
278 #endif
279 		break;
280 	case GIT_OPT_SET_USER_AGENT:
281 		git__free(git__user_agent);
282 		git__user_agent = git__strdup(va_arg(ap, const char *));
283 		if (!git__user_agent) {
284 			git_error_set_oom();
285 			error = -1;
286 		}
287 
288 		break;
289 
290 	case GIT_OPT_ENABLE_STRICT_OBJECT_CREATION:
291 		git_object__strict_input_validation = (va_arg(ap, int) != 0);
292 		break;
293 
294 	case GIT_OPT_ENABLE_STRICT_SYMBOLIC_REF_CREATION:
295 		git_reference__enable_symbolic_ref_target_validation = (va_arg(ap, int) != 0);
296 		break;
297 
298 	case GIT_OPT_SET_SSL_CIPHERS:
299 #if (GIT_OPENSSL || GIT_MBEDTLS)
300 		{
301 			git__free(git__ssl_ciphers);
302 			git__ssl_ciphers = git__strdup(va_arg(ap, const char *));
303 			if (!git__ssl_ciphers) {
304 				git_error_set_oom();
305 				error = -1;
306 			}
307 		}
308 #else
309 		git_error_set(GIT_ERROR_SSL, "TLS backend doesn't support custom ciphers");
310 		error = -1;
311 #endif
312 		break;
313 
314 	case GIT_OPT_GET_USER_AGENT:
315 		{
316 			git_buf *out = va_arg(ap, git_buf *);
317 			if ((error = git_buf_sanitize(out)) < 0)
318 				break;
319 			error = git_buf_sets(out, git__user_agent);
320 		}
321 		break;
322 
323 	case GIT_OPT_ENABLE_OFS_DELTA:
324 		git_smart__ofs_delta_enabled = (va_arg(ap, int) != 0);
325 		break;
326 
327 	case GIT_OPT_ENABLE_FSYNC_GITDIR:
328 		git_repository__fsync_gitdir = (va_arg(ap, int) != 0);
329 		break;
330 
331 	case GIT_OPT_GET_WINDOWS_SHAREMODE:
332 #ifdef GIT_WIN32
333 		*(va_arg(ap, unsigned long *)) = git_win32__createfile_sharemode;
334 #endif
335 		break;
336 
337 	case GIT_OPT_SET_WINDOWS_SHAREMODE:
338 #ifdef GIT_WIN32
339 		git_win32__createfile_sharemode = va_arg(ap, unsigned long);
340 #endif
341 		break;
342 
343 	case GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION:
344 		git_odb__strict_hash_verification = (va_arg(ap, int) != 0);
345 		break;
346 
347 	case GIT_OPT_SET_ALLOCATOR:
348 		error = git_allocator_setup(va_arg(ap, git_allocator *));
349 		break;
350 
351 	case GIT_OPT_ENABLE_UNSAVED_INDEX_SAFETY:
352 		git_index__enforce_unsaved_safety = (va_arg(ap, int) != 0);
353 		break;
354 
355 	case GIT_OPT_SET_PACK_MAX_OBJECTS:
356 		git_indexer__max_objects = va_arg(ap, size_t);
357 		break;
358 
359 	case GIT_OPT_GET_PACK_MAX_OBJECTS:
360 		*(va_arg(ap, size_t *)) = git_indexer__max_objects;
361 		break;
362 
363 	case GIT_OPT_DISABLE_PACK_KEEP_FILE_CHECKS:
364 		git_disable_pack_keep_file_checks = (va_arg(ap, int) != 0);
365 		break;
366 
367 	case GIT_OPT_ENABLE_HTTP_EXPECT_CONTINUE:
368 		git_http__expect_continue = (va_arg(ap, int) != 0);
369 		break;
370 
371 	default:
372 		git_error_set(GIT_ERROR_INVALID, "invalid option key");
373 		error = -1;
374 	}
375 
376 	va_end(ap);
377 
378 	return error;
379 }
380