From 9fcbbf319294ffa9baaeed37370ee4eab9772e29 Mon Sep 17 00:00:00 2001 From: Liam Waldron Date: Thu, 3 Apr 2025 15:07:08 -0400 Subject: [PATCH] Add file locking capabilities --- build/lib/libglacier.a | Bin 0 -> 20906 bytes build/lib/libglacier.o | Bin 0 -> 20016 bytes include/config.h | 75 ++--- include/data.h | 70 ++--- include/log.h | 48 ++-- include/pkgops.h | 93 +++--- include/runtime.h | 84 +++--- include/security.h | 117 +++----- src/libglacier.c | 628 +++++++++++++++++++++++++++++------------ tests/unit-tests.c | 28 +- 10 files changed, 645 insertions(+), 498 deletions(-) create mode 100644 build/lib/libglacier.a create mode 100644 build/lib/libglacier.o diff --git a/build/lib/libglacier.a b/build/lib/libglacier.a new file mode 100644 index 0000000000000000000000000000000000000000..9c764dc4bf7873e787b877c252675120239e463b GIT binary patch literal 20906 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 IukQc<1-5^2EdT%j literal 0 HcmV?d00001 diff --git a/build/lib/libglacier.o b/build/lib/libglacier.o new file mode 100644 index 0000000000000000000000000000000000000000..4bfb5cf7aabcc4e658babf41e92640489683c73f GIT binary patch literal 20016 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 _#{Khm zroiQRxXPzv#={c9m*ZirkN+#Kw=)3G3Y~hg)AajpAOCl(vtRIKy#;~Gaq<~~%W-m8 z=*w|(zra!D1UQPqw}p-zC%pofVF3OSfqz8k zy8@T`cLw1130(H?jtRcB^96xRJKqxc zO~Rf^zPC4i`z`ySig6^R{!)QELZ{xRGjSYcQg8%c>a+`d3-OG9cKUQ`S?4anm;U^e zkKf4r`vhOEpI;Ds9C=K=Ullm^mv+|qrqH=e@E;ApkNb4)V4WWa@LvqT{~+*?sF%K! zPyzjgzA^S!F%Il4G*EX5{D0sj0beT;va1b(Z)(*by1 z;I|3>qXOS1@FxW>+x0>K{&E2RMgV?Z;L@Ji=sXH&?{@l__ND^x{Q{Rd_X}LM>pKFM z{GSOtB7T&VK~p-wMD_3S9P!GLrt_+63!>3H&U+10Ub~&fpavZhlWNmIs;9F~2966R$Samz-xB7LdgifejJl4@u9ln6=u;_nO zIy>Ds6`=pfaO>y?#kK02P)@hTvvu?hVUm8{-AzJ}ciZS&;Yg>ed;OpPYm)@JmX|+I zu%4fu;dyE@co>+Z`u!W$lzI=*5A}6A?!#e<0$#IF*34sutq(9R=Q=^w6ufLxfVK?& z^i`AzO@I06T>c?hn4WE4dLgA@7Y`3F*OXu9bBwXy5OEiW^8WhUa7dzH+No2cf184L z;Bx*mKXh@pAp8eYO#Ma|?^39L0exiH$Mw&YAU%VNU}Btk%(KeiKZm)z#PICrwi1S` zWWWE8aCyI7#(roa?4=Jh{pC+_dHmi<27mcGD6^dZoEvqiTUZ$W!&QqZZ~RxTZj_vU xCH~U?+HnD#VNs92JkIz&6A7U(Pe)# literal 0 HcmV?d00001 diff --git a/include/config.h b/include/config.h index 0f0b006..d1348a6 100644 --- a/include/config.h +++ b/include/config.h @@ -26,67 +26,48 @@ #endif /* - * init_config + * gl_init_config * - * DESCRIPTION: Initialize libconfig with required configs - * PARAMETERS: - * None. - * RETURN VALUES: - * 0 on success, 1 on failure - * CAVEATS: - * This MUST be called before ANY other config function is. - * EXAMPLE: - * init_config(); + * DESCRIPTION: Initialize libconfig. + * PARAMETERS: None. + * RETURNS: 0 on success, EXIT_FAILURE on error */ - -int init_config(void); +int gl_init_config(void); /* - * die_config + * gl_die_config * - * DESCRIPTION: Die_config brings down libconfig gracefully. - * PARAMETERS: - * None. - * RETURN VALUES: - * 0 on success, 1 on failure - * CAVEATS: - * This MUST be called after ALL other config functions have completed. - * EXAMPLE: - * die_config(); + * DESCRIPTION: Kill libconfig. + * PARAMETERS: None. + * RETURNS: EXIT_SUCCESS on success */ - -int die_config(void); +int gl_die_config(void); /* - * load_all_from_config + * gl_load_all_from_config * - * DESCRIPTION: load_all_from_config loads all settings from the config file. - * PARAMETERS: - * None. - * RETURN VALUES: - * 0 on success, 1 on failure - * CAVEATS: - * None. - * EXAMPLE: - * load_all_from_config(); + * DESCRIPTION: Loads all settings from the Glacier config file. + * PARAMETERS: None. + * RETURNS: 0 on success, 1 on error */ - -int load_all_from_config(void); +int gl_load_all_from_config(void); /* - * load_all_from_profile + * gl_load_all_from_profile * - * DESCRIPTION: load_all_from_profile loads all settings from the profile file. - * PARAMETERS: - * None. - * RETURN VALUES: - * 0 on success, 1 on failure - * CAVEATS: - * None. - * EXAMPLE: - * load_all_from_profile(); + * DESCRIPTION: Loads all settings from the Glacier system profile. + * PARAMETERS: None. + * RETURNS: 0 on success, 1 on error */ +int gl_load_all_from_profile(void); -int load_all_from_profile(void); +/* + * gl_load_setting_from_config + * + * DESCRIPTION: Load a specified setting from the Glacier config file. + * PARAMETERS: char SETTING[] + * RETURNS: 0 on success, 1 on error + */ +int gl_load_setting_from_config(char SETTING[]); #endif diff --git a/include/data.h b/include/data.h index 6b3f7e4..c3bbc75 100644 --- a/include/data.h +++ b/include/data.h @@ -36,69 +36,39 @@ struct node { }; /* - * create_node + * gl_create_node * - * DESCRIPTION: Create_node creates a node for a dependency tree data structure. - * PARAMETERS: - * char *data -> The name of the node to create - * RETURN VALUES: - * A pointer to the created node on success, NULL on failure - * CAVEATS: - * Caller must free the node using free_node when done - * EXAMPLE: - * struct node *package = create_node("Package"); + * DESCRIPTION: Create a dependency tree node. + * PARAMETERS: char *data + * RETURNS: struct node* on success, NULL on failure */ - -struct node *create_node(char *data); +struct node *gl_create_node(char *data); /* - * free_node + * gl_free_node * - * DESCRIPTION: Free_node recursively frees all memory allocated for a node and its children. - * PARAMETERS: - * struct node *root -> The root node to free - * RETURN VALUES: - * None. - * CAVEATS: - * Will free all child nodes recursively. - * EXAMPLE: - * free_node(package); + * DESCRIPTION: Recursively free a node and all its children. + * PARAMETERS: struct node *root + * RETURNS: void */ - -void free_node(struct node *root); +void gl_free_node(struct node *root); /* - * add_child + * gl_add_child * - * DESCRIPTION: Add_child adds a child node to a parent node. - * PARAMETERS: - * struct node *parent -> The parent node which the child will be added to - * struct node *child -> The child node which will be added to the parent node - * RETURN VALUES: - * 0 on success, 1-3 for different error conditions - * CAVEATS: - * None. - * EXAMPLE: - * add_child(package, dep1); + * DESCRIPTION: Add a child node to a parent node. + * PARAMETERS: struct node *parent, struct node *child + * RETURNS: 0 on success, 1 on NULL pointer, 2 on invalid numChildren, 3 on max children exceeded */ - -int add_child(struct node *parent, struct node *child); +int gl_add_child(struct node *parent, struct node *child); /* - * print_tree + * gl_print_tree * - * DESCRIPTION: Print_tree prints a dependency tree specified at its root node. - * PARAMETERS: - * struct node *root -> The tree to print - * int level -> The number of levels to descend - * RETURN VALUES: - * 0 on success, non-zero on error - * CAVEATS: - * None. - * EXAMPLE: - * print_tree(package, 0); + * DESCRIPTION: Print a dependency tree. + * PARAMETERS: struct node *root, int level + * RETURNS: 0 on success, 1 on invalid level, 2 on max recursion depth exceeded, 3 on invalid numChildren, 4 on child print error */ - -int print_tree(struct node *root, int level); +int gl_print_tree(struct node *root, int level); #endif diff --git a/include/log.h b/include/log.h index 2e3e36e..b1b32c8 100644 --- a/include/log.h +++ b/include/log.h @@ -19,81 +19,73 @@ #define GLACIERLOG_H_ /* - * infolog + * gl_infolog * - * DESCRIPTION: Infolog outputs a stylized info message. It follows Glacier's uniform CLI style. + * DESCRIPTION: gl_infolog outputs a stylized info message. It follows Glacier's uniform CLI style. * PARAMETERS: * char MSG[] -> The message to output * RETURN VALUES: * None. * CAVEATS: - * * Cannot output variables. If you must output variables, use printf instead. - * * A NEWLINE ('\n') character is implied, therefore putting one at the end of - * a string is not needed. + * None. * EXAMPLE: - * infolog("This is an info message."); + * gl_infolog("This is an info message."); */ -void infolog(char MSG[]); +void gl_infolog(char MSG[]); /**************************************************************************************************************/ /* - * warnlog + * gl_warnlog * - * DESCRIPTION: Warnlog outputs a stylized warning message. It follows Glacier's uniform CLI style. + * DESCRIPTION: gl_warnlog outputs a stylized warning message. It follows Glacier's uniform CLI style. * PARAMETERS: * char MSG[] -> The message to output * RETURN VALUES: * None. * CAVEATS: - * * Cannot output variables. If you must output variables, use printf instead. - * * A NEWLINE ('\n') character is implied, therefore putting one at the end of - * a string is not needed. + * None. * EXAMPLE: - * warnlog("This is a warning message."); + * gl_warnlog("This is a warning message."); */ -void warnlog(char MSG[]); +void gl_warnlog(char MSG[]); /**************************************************************************************************************/ /* - * errlog + * gl_errlog * - * DESCRIPTION: Errlog outputs a stylized error message. It follows Glacier's uniform CLI style. + * DESCRIPTION: gl_errlog outputs a stylized error message. It follows Glacier's uniform CLI style. * PARAMETERS: * char MSG[] -> The message to output * RETURN VALUES: * None. * CAVEATS: - * * Cannot output variables. If you must output variables, use printf instead. - * * A NEWLINE ('\n') character is implied, therefore putting one at the end of - * a string is not needed. + * None. * EXAMPLE: - * errlog("This is an error message."); + * gl_errlog("This is an error message."); */ -void errlog(char MSG[]); +void gl_errlog(char MSG[]); /**************************************************************************************************************/ /* - * successlog + * gl_successlog * - * DESCRIPTION: Successlog outputs a stylized success message. It follows Glacier's uniform CLI style. + * DESCRIPTION: gl_successlog outputs a stylized success message. It follows Glacier's uniform CLI style. * PARAMETERS: * char MSG[] -> The message to output * RETURN VALUES: * None. * CAVEATS: - * * Cannot output variables. If you must output variables, use printf instead. - * * A NEWLINE ('\n') character is implied, therefore putting one at the end of - * a string is not needed. + * None. * EXAMPLE: - * successlog("This is a success message."); + * gl_successlog("This is a success message."); */ -void successlog(char MSG[]); +void gl_successlog(char MSG[]); #endif diff --git a/include/pkgops.h b/include/pkgops.h index 65dae07..0f8011c 100644 --- a/include/pkgops.h +++ b/include/pkgops.h @@ -25,54 +25,77 @@ #define PATH_MAX_SIZE 512 /* - * mkworkspace + * gl_mkworkspace + * + * DESCRIPTION: gl_mkworkspace prepares /tmp/glacier-workspace for an operation * - * DESCRIPTION: Mkworkspace prepares /tmp/glacier-workspace for an operation - * PARAMETERS: - * None. - * RETURN VAUES: - * 0 on workspace already exists, 1 on workspace created, -1 on error - * CAVEATS: - * None. * EXAMPLE: - * mkworkspace(); + * gl_mkworkspace(); + * + * RETURNS: 0 on success, 1 if workspace already exists, -1 on failure */ - -int mkworkspace(void); +int gl_mkworkspace(void); /* - * prepare_pkg + * gl_prepare_pkg + * + * DESCRIPTION: gl_prepare_pkg copies a package archive from the localdb, and untars it * - * DESCRIPTION: Prepare_pkg copies a package archive from the localdb, and untars it - * PARAMETERS: - * char PACKAGE[] -> The package file to prepare - * RETURN VAUES: - * 0 on success, 1 on package does not exist or error, other values for specific errors - * CAVEATS: - * The example presented is bad. You should be calling the system profile variable - * rather than manually specifying one. * EXAMPLE: - * prepare_pkg("/glacier/localdb/epkgs-x86_64-musl/foo.tar"); + * gl_prepare_pkg("/glacier/localdb/epkgs-x86_64-musl/foo.tar"); + * + * RETURNS: 0 on success, 1 on failure */ - -int prepare_pkg(char PACKAGE[]); +int gl_prepare_pkg(char PACKAGE[]); /* - * run_make_task + * gl_run_make_task + * + * DESCRIPTION: gl_run_make_task runs a specified make task in a package's current working directory * - * DESCRIPTION: Run_make_task runs a specified make task in a package's current working directory - * PARAMETERS: - * char TASK[] -> The make task to run - * RETURN VAUES: - * 0 on success, other values for specific errors - * CAVEATS: - * MUST be run after prepare_pkg(), or else errors will occur - * Same caveat as above. Do not manually specify the system profile, use its variable. * EXAMPLE: - * prepare_pkg("/glacier/localdb/epkgs-x86_64-musl/foo.tar"); - * run_make_task("installpkg"); + * MUST be run after gl_prepare_pkg(), or else errors will occur + * gl_prepare_pkg("/glacier/localdb/epkgs-x86_64-musl/foo.tar"); + * gl_run_make_task("installpkg"); + * + * RETURNS: 0 on success, 1 on failure + */ +int gl_run_make_task(char TASK[]); + +/* + * gl_lock_file + * + * DESCRIPTION: Locks a specified file using fcntl + * PARAMETERS: + * const char *filepath -> The path to the file to lock + * RETURN VALUES: + * File descriptor on success, -1 on failure + * CAVEATS: + * The returned file descriptor must be passed to gl_unlock_file() to release the lock + * EXAMPLE: + * int fd = gl_lock_file("/path/to/file"); + * if (fd >= 0) { + * // Do work with locked file + * gl_unlock_file(fd); + * } */ -int run_make_task(char TASK[]); +int gl_lock_file(const char *filepath); + +/* + * gl_unlock_file + * + * DESCRIPTION: Unlocks a specified file using fcntl + * PARAMETERS: + * int file_descriptor -> The file descriptor returned by gl_lock_file() + * RETURN VALUES: + * 0 on success, 1 on failure + * CAVEATS: + * Only the process that acquired the lock can release it + * EXAMPLE: + * gl_unlock_file(file_descriptor); + */ + +int gl_unlock_file(int file_descriptor); #endif diff --git a/include/runtime.h b/include/runtime.h index b537e80..27eeecb 100644 --- a/include/runtime.h +++ b/include/runtime.h @@ -19,68 +19,48 @@ #define GLACIERRUNTIME_H_ /* - * runtime_exists + * gl_runtime_exists * - * DESCRIPTION: runtime_exists checks if all necessary runtime files exist. - * PARAMETERS: - * None. (void) - * RETURN VALUES: - * 0 on one or more runtime files missing, 1 on all runtime files exist - * CAVEATS: - * None. - * EXAMPLE: - * if (runtime_exists() == 0) { - * errlog("One or more runtime files missing"); - * return 1; - * } - * else { - * successlog("All runtime files present"); - * return 0; - * } + * DESCRIPTION: Check if necessary runtime files exist. + * PARAMETERS: None. + * RETURNS: 1 if all files exist, 0 if any file is missing */ - -int runtime_exists(void); +int gl_runtime_exists(void); /* - * is_process_root + * gl_is_process_root * - * DESCRIPTION: is_process_root checks if the process is running with root privileges. - * PARAMETERS: - * None. (void) - * RETURN VALUES: - * 0 on process is not running as root, 1 on process is running as root - * CAVEATS: - * None. - * EXAMPLE: - * // Assuming block is running within main(), no values will be returned. - * // If you wish to exit the program if it is not running as root, it would - * // be appropriate to add return values to this block - * - * if (is_process_root() == 0) { - * errlog("Process is not running as root"); - * } - * else { - * successlog("Process is running as root"); - * } + * DESCRIPTION: Check if process is running as root. + * PARAMETERS: None. + * RETURNS: 1 if running as root, 0 otherwise */ - -int is_process_root(void); +int gl_is_process_root(void); /* - * get_system_profile + * gl_get_system_profile * - * DESCRIPTION: get_system_profile fetches the system profile, which contains information about the architecture and libc implementation. - * PARAMETERS: - * None. (void) - * RETURN VALUES: - * A pointer to a string containing the system profile (e.g., "x86_64-musl"). - * CAVEATS: - * None. - * EXAMPLE: - * char *profile = get_system_profile(); - * infolog(profile); + * DESCRIPTION: Get the current system profile. + * PARAMETERS: None. + * RETURNS: char* containing the system profile name */ +char *gl_get_system_profile(void); -char *get_system_profile(void); +/* + * gl_lock_file + * + * DESCRIPTION: Locks a specified file using fcntl. + * PARAMETERS: const char *filepath - Path to the file to lock + * RETURNS: file descriptor on success, -1 on failure + */ +int gl_lock_file(const char *filepath); + +/* + * gl_unlock_file + * + * DESCRIPTION: Unlocks a specified file using fcntl. + * PARAMETERS: int file_descriptor - The file descriptor of the locked file + * RETURNS: 0 on success, -1 on failure + */ +int gl_unlock_file(int file_descriptor); #endif diff --git a/include/security.h b/include/security.h index 680abf5..2889976 100644 --- a/include/security.h +++ b/include/security.h @@ -39,101 +39,48 @@ typedef unsigned char uchar; /* int compare_file_hash(char ORIG_HASH[], char FILE[]); */ /* - * hash_file + * gl_print_hash + * + * DESCRIPTION: Prints a specified hash string + * PARAMETERS: unsigned char *hash, unsigned int length + * RETURNS: 0 on success, 1 on error + */ +int gl_print_hash(uchar *hash, uint length); + +/* + * gl_stash_hash + * + * DESCRIPTION: Stores a hash inside a string + * PARAMETERS: unsigned char *stored_hash, unsigned char *hash, unsigned int length + * RETURNS: 0 on success, 1 on error + */ +int gl_stash_hash(char *stored_hash, unsigned int stored_hash_size, const uchar *hash, uint length); + +/* + * gl_hash_file * * DESCRIPTION: Performs a hashing operation on a file and stores the result - * PARAMETERS: - * const char *filename -> The file to hash - * unsigned char *out_hash -> Buffer to store the resulting hash - * unsigned int *out_length -> Will contain the length of the hash - * RETURN VALUES: - * 0 on success, other values for specific errors - * CAVEATS: - * out_hash buffer must be large enough to hold the hash (EVP_MAX_MD_SIZE recommended) - * EXAMPLE: - * unsigned char hash[EVP_MAX_MD_SIZE]; - * unsigned int hash_len; - * hash_file("file.txt", hash, &hash_len); + * PARAMETERS: const char *filename, unsigned char *out_hash, unsigned int *out_length + * RETURNS: 0 on success, 1-6 for different error conditions */ - -int hash_file(const char *filename, unsigned char *out_hash, unsigned int *out_length); +int gl_hash_file(const char *filename, unsigned char *out_hash, unsigned int *out_length); /* - * print_hash + * gl_verify_signature * - * DESCRIPTION: Prints a specified hash string to stdout - * PARAMETERS: - * unsigned char *hash -> The hash to print - * unsigned int length -> Length of the hash - * RETURN VALUES: - * 0 on success, 1 on error - * CAVEATS: - * None - * EXAMPLE: - * print_hash(hash, hash_len); + * DESCRIPTION: Verify a package signature against a trusted keyring + * PARAMETERS: char PACKAGE[], char SIGNATURE[] + * RETURNS: 0 on success, 1 on verification failure, 2 on file not found */ - -int print_hash(uchar *hash, uint length); +int gl_verify_signature(char PACKAGE[], char SIGNATURE[]); /* - * stash_hash + * gl_check_integrity * - * DESCRIPTION: Stores a hash inside a string as hexadecimal representation - * PARAMETERS: - * char *stored_hash -> Buffer to store the resulting hash string - * unsigned int stored_hash_size -> Size of the stored_hash buffer - * const uchar *hash -> The hash to convert to string - * uint length -> Length of the hash - * RETURN VALUES: - * 0 on success, 1 on error - * CAVEATS: - * stored_hash buffer must be at least (length*2)+1 bytes in size - * EXAMPLE: - * char hash_str[65]; // 32 bytes SHA-256 = 64 hex chars + null terminator - * stash_hash(hash_str, sizeof(hash_str), hash, hash_len); + * DESCRIPTION: Check package integrity by comparing with expected hash + * PARAMETERS: char PACKAGE[], char EXPECTED_HASH[] + * RETURNS: 0 on success, 1 on hash mismatch, 2 on file not found or error */ - -int stash_hash(char *stored_hash, unsigned int stored_hash_size, const uchar *hash, uint length); - -/* - * verify_signature - * - * DESCRIPTION: Checks if a package's signature is valid against the trusted keyring - * PARAMETERS: - * char PACKAGE[] -> The package file to verify - * char SIGNATURE[] -> The signature file to check against - * RETURN VALUES: - * 0 on valid signature, 1 on invalid signature, 2 on file not found - * CAVEATS: - * None - * EXAMPLE: - * if (verify_signature("package.tar", "package.tar.sig") != 0) { - * errlog("invalid package signature"); - * return(EXIT_FAILURE); - * } - */ - -int verify_signature(char PACKAGE[], char SIGNATURE[]); - -/* - * check_integrity - * - * DESCRIPTION: Verifies a package's SHA256 checksum against the expected value - * PARAMETERS: - * char PACKAGE[] -> The package file to check - * char EXPECTED_HASH[] -> The expected SHA256 hash - * RETURN VALUES: - * 0 on hash match, 1 on hash mismatch, 2 on file not found or hash calculation error - * CAVEATS: - * None - * EXAMPLE: - * char *expected = "d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592"; - * if (check_integrity("package.tar", expected) != 0) { - * errlog("package integrity check failed"); - * return(EXIT_FAILURE); - * } - */ - -int check_integrity(char PACKAGE[], char EXPECTED_HASH[]); +int gl_check_integrity(char PACKAGE[], char EXPECTED_HASH[]); #endif diff --git a/src/libglacier.c b/src/libglacier.c index f5a49f7..3f3aa3d 100644 --- a/src/libglacier.c +++ b/src/libglacier.c @@ -15,16 +15,21 @@ * not, see . */ +#define _POSIX_C_SOURCE 200809L + #include #include #include +#include #include #include #include +#include #include #include #include #include +#include /* For strcasecmp */ #include #include #include @@ -60,7 +65,7 @@ typedef unsigned char uchar; config_t cfg; /* Context for libconfig */ config_setting_t *setting = NULL; /* Pointer for setting */ -/* Configuration variables with default values */ +/* Con:figuration variables with default values */ int GLACIER_ALLOW_SERVICES = 0; /* Declaration of GLACIER_ALLOW_SERVICES as given in glacier.cfg */ char *GLACIER_ALLOWED_LICENSES = NULL; /* Declaration of GLACIER_ALLOWED_LICENSES as given in glacier.cfg */ int GLACIER_DO_INT_CHECK = 1; /* Declaration of GLACIER_DO_INT_CHECK as given in glacier.cfg */ @@ -104,7 +109,7 @@ struct node { }; /* - * infolog + * gl_infolog * * DESCRIPTION: Output a stylized info message. * PARAMETERS: char MSG[] @@ -113,7 +118,7 @@ struct node { */ void -infolog(char MSG[]) +gl_infolog(char MSG[]) { if (MSG == NULL) { return; @@ -124,7 +129,7 @@ infolog(char MSG[]) } /* - * warnlog + * gl_warnlog * * DESCRIPTION: Output a stylized warning message. * Parameters: char MSG[] @@ -133,7 +138,7 @@ infolog(char MSG[]) */ void -warnlog(char MSG[]) +gl_warnlog(char MSG[]) { if (MSG == NULL) { return; @@ -144,7 +149,7 @@ warnlog(char MSG[]) } /* - * errlog + * gl_errlog * * DESCRIPTION: Output a stylized error message. * PARAMETERS: char MSG[] @@ -153,7 +158,7 @@ warnlog(char MSG[]) */ void -errlog(char MSG[]) +gl_errlog(char MSG[]) { if (MSG == NULL) { return; @@ -164,7 +169,7 @@ errlog(char MSG[]) } /* - * successlog + * gl_successlog * * DESCRIPTION: Output a stylized success message. * PARAMETERS: char MSG[] @@ -173,7 +178,7 @@ errlog(char MSG[]) */ void -successlog(char MSG[]) +gl_successlog(char MSG[]) { if (MSG == NULL) { return; @@ -184,7 +189,7 @@ successlog(char MSG[]) } /* - * runtime_exists + * gl_runtime_exists * * DESCRIPTION: Check if necesary runtime files exist. * PARAMETERS: None. @@ -193,7 +198,7 @@ successlog(char MSG[]) */ int -runtime_exists(void) +gl_runtime_exists(void) { int f; @@ -212,7 +217,7 @@ runtime_exists(void) } /* - * is_process_root + * gl_is_process_root * * DESCRIPTION: Check if process is running as root. * PARAMETERS: char MSG[] @@ -221,7 +226,7 @@ runtime_exists(void) */ int -is_process_root(void) +gl_is_process_root(void) { if (getuid() != 0) { return 0; /* process is not running as root */ @@ -232,7 +237,7 @@ is_process_root(void) } /* - * init_config + * gl_init_config * * DESCRIPTION: Initialize libconfig. * PARAMETERS: None. @@ -241,7 +246,7 @@ is_process_root(void) */ int -init_config(void) +gl_init_config(void) { config_init(&cfg); @@ -253,14 +258,14 @@ init_config(void) } if (LG_VERBOSE == 1) { - infolog("Initialized libconfig"); + gl_infolog("Initialized libconfig"); } return 0; } /* - * die_config + * gl_die_config * * DESCRIPTION: Kill libconfig. * PARAMETERS: None. @@ -269,19 +274,19 @@ init_config(void) */ int -die_config(void) +gl_die_config(void) { config_destroy(&cfg); if (LG_VERBOSE == 1) { - infolog("Destroyed libconfig"); + gl_infolog("Destroyed libconfig"); } return(EXIT_SUCCESS); } /* - * load_all_from_config + * gl_load_all_from_config * * DESCRIPTION: Loads all settings from the Glacier config file. * PARAMETERS: None. @@ -290,7 +295,7 @@ die_config(void) */ int -load_all_from_config(void) +gl_load_all_from_config(void) { /* this is probably really ugly but it works */ if (! config_lookup_bool(&cfg, "GLACIER_DO_INT_CHECK", &GLACIER_DO_INT_CHECK)) { return 1; } @@ -300,7 +305,7 @@ load_all_from_config(void) } /* - * load_all_from_profile + * gl_load_all_from_profile * * DESCRIPTION: Loads all settings from the Glacier system profile. * PARAMETERS: None. @@ -309,7 +314,7 @@ load_all_from_config(void) */ int -load_all_from_profile(void) +gl_load_all_from_profile(void) { if (! config_lookup_string(&cfg, "GLACIER_REPO", &GLACIER_REPO)) { return 1; } if (! config_lookup_string(&cfg, "GLACIER_ARCH", &GLACIER_ARCH)) { return 1; } @@ -320,7 +325,7 @@ load_all_from_profile(void) } /* - * load_setting_from_config + * gl_load_setting_from_config * * DESCRIPTION: Load a specified setting from the Glacier config file. * PARAMETERS: char SETTING[] @@ -333,7 +338,7 @@ load_setting_from_config(char SETTING[]) {} */ /* -* create_node +* gl_create_node * * DESCRIPTION: Create a dependency tree node. * PARAMETERS: char *data @@ -342,22 +347,22 @@ load_setting_from_config(char SETTING[]) */ struct node -*create_node(char *data) +*gl_create_node(char *data) { if (data == NULL) { - if (LG_VERBOSE == 1) { errlog("NULL data passed to create_node()"); } + if (LG_VERBOSE == 1) { gl_errlog("NULL data passed to gl_create_node()"); } return NULL; } struct node *newNode = (struct node*)malloc(sizeof(struct node)); if (newNode == NULL) { - if (LG_VERBOSE == 1) { errlog("Memory allocation failed in create_node()"); } + if (LG_VERBOSE == 1) { gl_errlog("Memory allocation failed in gl_create_node()"); } return NULL; } newNode->data = strdup(data); if (newNode->data == NULL) { - if (LG_VERBOSE == 1) { errlog("String duplication failed in create_node()"); } + if (LG_VERBOSE == 1) { gl_errlog("String duplication failed in gl_create_node()"); } free(newNode); return NULL; } @@ -374,7 +379,7 @@ struct node } /* - * free_node + * gl_free_node * * DESCRIPTION: Recursively free a node and all its children. * PARAMETERS: struct node *root @@ -383,7 +388,7 @@ struct node */ void -free_node(struct node *root) +gl_free_node(struct node *root) { if (root == NULL) { return; @@ -391,7 +396,7 @@ free_node(struct node *root) /* Free all children recursively */ for (int i = 0; i < root->numChildren; i++) { - free_node(root->children[i]); + gl_free_node(root->children[i]); } /* Free data string */ @@ -404,7 +409,7 @@ free_node(struct node *root) } /* - * add_child + * gl_add_child * * DESCRIPTION: Add a child node to a parent node. * PARAMETERS: struct node *parent, struct node *child @@ -413,18 +418,18 @@ free_node(struct node *root) */ int -add_child(struct node *parent, struct node *child) +gl_add_child(struct node *parent, struct node *child) { if (parent == NULL || child == NULL) { if (LG_VERBOSE == 1) { - errlog("NULL pointer passed to add_child()"); + gl_errlog("NULL pointer passed to gl_add_child()"); } return 1; } if (parent->numChildren < 0 || parent->numChildren >= MAX_CHILDREN) { if (LG_VERBOSE == 1) { - errlog("Invalid numChildren value in parent node"); + gl_errlog("Invalid numChildren value in parent node"); } return 2; } @@ -434,14 +439,14 @@ add_child(struct node *parent, struct node *child) return 0; } else { if (LG_VERBOSE == 1) { - errlog("Maximum number of children exceeded"); + gl_errlog("Maximum number of children exceeded"); } return 3; } } /* -* print_tree +* gl_print_tree * * DESCRIPTION: Print a dependency tree. * PARAMETERS: struct node *root, int level @@ -450,7 +455,7 @@ add_child(struct node *parent, struct node *child) */ int -print_tree(struct node *root, int level) +gl_print_tree(struct node *root, int level) { if (root == NULL) { return 0; @@ -458,7 +463,7 @@ print_tree(struct node *root, int level) if (level < 0) { if (LG_VERBOSE == 1) { - errlog("Invalid level value in print_tree()"); + gl_errlog("Invalid level value in gl_print_tree()"); } return 1; } @@ -466,7 +471,7 @@ print_tree(struct node *root, int level) if (level > MAX_RECURSION_DEPTH) { /* Safety check to prevent stack overflow from recursive calls */ if (LG_VERBOSE == 1) { - errlog("Maximum recursion depth exceeded in print_tree()"); + gl_errlog("Maximum recursion depth exceeded in gl_print_tree()"); } return 2; } @@ -483,13 +488,13 @@ print_tree(struct node *root, int level) if (root->numChildren < 0 || root->numChildren > MAX_CHILDREN) { if (LG_VERBOSE == 1) { - errlog("Invalid numChildren value in node"); + gl_errlog("Invalid numChildren value in node"); } return 3; } for (int i = 0; i < root->numChildren; i++) { - if (print_tree(root->children[i], level + 1) != 0) { + if (gl_print_tree(root->children[i], level + 1) != 0) { /* Propagate errors up the call stack */ return 4; } @@ -499,7 +504,7 @@ print_tree(struct node *root, int level) } /* - * mkworkspace + * gl_mkworkspace * * DESCRIPTION: Creates a new Glacier workspace in /tmp. * PARAMETERS: None. @@ -508,7 +513,7 @@ print_tree(struct node *root, int level) */ int -mkworkspace(void) +gl_mkworkspace(void) { const char *workspace_path = "/tmp/glacier-workspace"; @@ -516,14 +521,14 @@ mkworkspace(void) if (workspace) { /* Workspace exists */ closedir(workspace); - /* infolog("Not creating new workspace, valid workspace already exists."); */ + /* gl_infolog("Not creating new workspace, valid workspace already exists."); */ return 0; } else if (ENOENT == errno) { - /* infolog("Creating new Glacier workspace..."); */ + /* gl_infolog("Creating new Glacier workspace..."); */ if (mkdir(workspace_path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0) { if (LG_VERBOSE == 1) { - errlog("in mkworkspace()"); - errlog("mkdir() failed to create workspace directory"); + gl_errlog("in gl_mkworkspace()"); + gl_errlog("mkdir() failed to create workspace directory"); fprintf(stderr, "Error: %s\n", strerror(errno)); } return -1; @@ -532,8 +537,8 @@ mkworkspace(void) } else { /* Some other error occurred */ if (LG_VERBOSE == 1) { - errlog("in mkworkspace()"); - errlog("opendir() failed to check workspace"); + gl_errlog("in gl_mkworkspace()"); + gl_errlog("opendir() failed to check workspace"); fprintf(stderr, "Error: %s\n", strerror(errno)); } return -1; @@ -541,7 +546,7 @@ mkworkspace(void) } /* - * prepare_pkg + * gl_prepare_pkg * * DESCRIPTION: Copies a package archive from the localdb to the workspace, and unpacks it. * PARAMETERS: char PACKAGE[] @@ -550,99 +555,122 @@ mkworkspace(void) */ int -prepare_pkg(char PACKAGE[]) +gl_prepare_pkg(char PACKAGE[]) { if (PACKAGE == NULL) { printf(COL_RED "[x] " COL_RESET "Package '%s' does not exist in the local database.\n", PACKAGE); - errlog("Ensure your local database is up to date and try again."); - errlog("This can be done by running 'glacier-update-pkgdb' as root."); + gl_errlog("Ensure your local database is up to date and try again."); + gl_errlog("This can be done by running 'glacier-update-pkgdb' as root."); return 1; + } + + /* Get just the package name without path and extension */ + char pkg_name[PATH_MAX_SIZE]; + const char *last_slash = strrchr(PACKAGE, '/'); + const char *last_dot = strrchr(PACKAGE, '.'); + + if (last_slash == NULL) { + /* No path separator found, use whole string */ + strncpy(pkg_name, PACKAGE, sizeof(pkg_name) - 1); } else { - char PKG_NEW[PATH_MAX_SIZE]; - PKG_NEW[0] = '\0'; /* Initialize the string buffer */ - snprintf(PKG_NEW, sizeof(PKG_NEW), "/tmp/glacier-workspace/%s.tar", PACKAGE); - - FILE *pkg_old, *pkg_new; - char buffer[BUFFER_SIZE]; - size_t bytes_read; + /* Copy everything after the last slash */ + strncpy(pkg_name, last_slash + 1, sizeof(pkg_name) - 1); + } + + /* Remove .tar extension if present */ + if (last_dot != NULL && strcmp(last_dot, ".tar") == 0) { + pkg_name[strlen(pkg_name) - 4] = '\0'; + } - pkg_old = fopen(PACKAGE, "rb"); - if (pkg_old == NULL) { - errlog("Failed to open source package file"); - return 1; - } - - pkg_new = fopen(PKG_NEW, "wb"); - if (pkg_new == NULL) { - errlog("Failed to create destination package file"); - fclose(pkg_old); - return 1; - } - - /* Use buffered I/O for better efficiency */ - while ((bytes_read = fread(buffer, 1, sizeof(buffer), pkg_old)) > 0) { - if (fwrite(buffer, 1, bytes_read, pkg_new) != bytes_read) { - errlog("Failed to write to destination file"); - fclose(pkg_old); - fclose(pkg_new); - return 1; - } - } + /* Construct the workspace path */ + char PKG_NEW[PATH_MAX_SIZE]; + snprintf(PKG_NEW, sizeof(PKG_NEW), "/tmp/glacier-workspace/%s.tar", pkg_name); + + FILE *pkg_old, *pkg_new; + char buffer[BUFFER_SIZE]; + size_t bytes_read; + pkg_old = fopen(PACKAGE, "rb"); + if (pkg_old == NULL) { + gl_errlog("Failed to open source package file"); + return 1; + } + + pkg_new = fopen(PKG_NEW, "wb"); + if (pkg_new == NULL) { + gl_errlog("Failed to create destination package file"); fclose(pkg_old); - fclose(pkg_new); - - /* Fork before exec to prevent process replacement */ - pid_t pid = fork(); - if (pid < 0) { - errlog("Failed to fork process"); - return 1; - } else if (pid == 0) { - /* Child process */ - char *tar_args[] = { - "/bin/tar", /* This should be changed to /glacier/bin/tar later on */ - "-xvf", - PKG_NEW, - NULL, - }; + return 1; + } - execvp("/bin/tar", tar_args); - /* If we get here, execvp failed */ - fprintf(stderr, COL_RED "[x] " COL_RESET "Failed to execute tar: %s\n", strerror(errno)); - exit(EXIT_FAILURE); - } else { - /* Parent process */ - int status; - waitpid(pid, &status, 0); - - if (WIFEXITED(status) && WEXITSTATUS(status) != 0) { - printf(COL_RED "[x] " COL_RESET "Error while unpacking archive for package %s.\n", PACKAGE); - return WEXITSTATUS(status); - } - - if (remove(PKG_NEW) != 0) { - warnlog("Failed to remove temporary package file"); - } - - char pkg_dir[PATH_MAX_SIZE]; - pkg_dir[0] = '\0'; /* Initialize the string buffer */ - snprintf(pkg_dir, sizeof(pkg_dir), "/tmp/glacier-workspace/%s", PACKAGE); - - if (chdir(pkg_dir) != 0) { - errlog("Failed to change directory"); - return 1; - } - - return 0; + /* Use buffered I/O for better efficiency */ + while ((bytes_read = fread(buffer, 1, sizeof(buffer), pkg_old)) > 0) { + if (fwrite(buffer, 1, bytes_read, pkg_new) != bytes_read) { + gl_errlog("Failed to write to destination file"); + fclose(pkg_old); + fclose(pkg_new); + return 1; } } + + fclose(pkg_old); + fclose(pkg_new); + + /* Create the package directory first */ + char pkg_dir[PATH_MAX_SIZE]; + snprintf(pkg_dir, sizeof(pkg_dir), "/tmp/glacier-workspace/%s", pkg_name); + if (mkdir(pkg_dir, DEFAULT_PERMISSIONS) != 0 && errno != EEXIST) { + gl_errlog("Failed to create package directory"); + return 1; + } + + /* Change to the package directory before extracting */ + if (chdir(pkg_dir) != 0) { + gl_errlog("Failed to change to package directory"); + return 1; + } + + /* Fork before exec to prevent process replacement */ + pid_t pid = fork(); + if (pid < 0) { + gl_errlog("Failed to fork process"); + return 1; + } else if (pid == 0) { + /* Child process */ + char *tar_args[] = { + "/usr/bin/bsdtar", /* Using bsdtar instead of GNU tar */ + "-xf", /* Extract without verbose output */ + PKG_NEW, + NULL, + }; + + execvp("/usr/bin/bsdtar", tar_args); + /* If we get here, execvp failed */ + fprintf(stderr, COL_RED "[x] " COL_RESET "Failed to execute bsdtar: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } else { + /* Parent process */ + int status; + waitpid(pid, &status, 0); + + if (WIFEXITED(status) && WEXITSTATUS(status) != 0) { + printf(COL_RED "[x] " COL_RESET "Error while unpacking archive for package %s.\n", pkg_name); + return WEXITSTATUS(status); + } + + if (remove(PKG_NEW) != 0) { + gl_warnlog("Failed to remove temporary package file"); + } + + return 0; + } /* Should never reach here, but added for completeness */ return 1; } /* - * run_make_task + * gl_run_make_task * * DESCRIPTION: Runs a make task in current working directory * PARAMETERS: char TASK[] @@ -651,17 +679,17 @@ prepare_pkg(char PACKAGE[]) */ int -run_make_task(char TASK[]) +gl_run_make_task(char TASK[]) { if (TASK == NULL) { - errlog("No task specified for make"); + gl_errlog("No task specified for make"); return 1; } /* Fork before exec to prevent process replacement */ pid_t pid = fork(); if (pid < 0) { - errlog("Failed to fork process"); + gl_errlog("Failed to fork process"); return 1; } else if (pid == 0) { /* Child process */ @@ -673,7 +701,7 @@ run_make_task(char TASK[]) execvp("/bin/make", build_args); /* If we get here, execvp failed */ - errlog("Failed to execute make"); + gl_errlog("Failed to execute make"); fprintf(stderr, "Error: %s\n", strerror(errno)); exit(EXIT_FAILURE); } else { @@ -684,7 +712,7 @@ run_make_task(char TASK[]) if (WIFEXITED(status)) { return WEXITSTATUS(status); } else { - errlog("Make process terminated abnormally"); + gl_errlog("Make process terminated abnormally"); return 1; } } @@ -694,7 +722,7 @@ run_make_task(char TASK[]) } /* - * print_hash + * gl_print_hash * * DESCRIPTION: Prints a specified hash string * PARAMETERS: unsigned char *hash, unsigned int length @@ -703,15 +731,15 @@ run_make_task(char TASK[]) */ int -print_hash(uchar *hash, uint length) +gl_print_hash(uchar *hash, uint length) { if (hash == NULL) { - errlog("NULL hash pointer passed to print_hash()"); + gl_errlog("NULL hash pointer passed to gl_print_hash()"); return 1; } if (length == 0) { - warnlog("Zero-length hash passed to print_hash()"); + gl_warnlog("Zero-length hash passed to gl_print_hash()"); } for (uint index = 0; index < length; index++) { @@ -724,7 +752,7 @@ print_hash(uchar *hash, uint length) } /* - * stash_hash + * gl_stash_hash * * DESCRIPTION: Stores a hash inside a string * PARAMETERS: unsigned char *stored_hash, unsigned char *hash, unsigned int length @@ -733,20 +761,20 @@ print_hash(uchar *hash, uint length) */ int -stash_hash(char *stored_hash, unsigned int stored_hash_size, const uchar *hash, uint length) +gl_stash_hash(char *stored_hash, unsigned int stored_hash_size, const uchar *hash, uint length) { if (stored_hash == NULL || hash == NULL) { if (LG_VERBOSE == 1) { - errlog("in stash_hash()"); - errlog("NULL pointer provided"); + gl_errlog("in gl_stash_hash()"); + gl_errlog("NULL pointer provided"); } return 1; } if (stored_hash_size < (length * 2 + 1)) { if (LG_VERBOSE == 1) { - errlog("in stash_hash()"); - errlog("Output buffer too small for hash"); + gl_errlog("in gl_stash_hash()"); + gl_errlog("Output buffer too small for hash"); } return 1; } @@ -765,7 +793,7 @@ stash_hash(char *stored_hash, unsigned int stored_hash_size, const uchar *hash, } /* - * hash_file + * gl_hash_file * * DESCRIPTION: Performs a hashing operation on a file and stores the result * PARAMETERS: const char *filename @@ -774,12 +802,12 @@ stash_hash(char *stored_hash, unsigned int stored_hash_size, const uchar *hash, */ int -hash_file(const char *filename, unsigned char *out_hash, unsigned int *out_length) +gl_hash_file(const char *filename, unsigned char *out_hash, unsigned int *out_length) { FILE *data = fopen(filename, "rb"); if (! data && LG_VERBOSE == 1) { - errlog("in hash_file()"); - errlog("error opening file handle"); + gl_errlog("in gl_hash_file()"); + gl_errlog("error opening file handle"); return 1; } else if (! data) { @@ -788,8 +816,8 @@ hash_file(const char *filename, unsigned char *out_hash, unsigned int *out_lengt EVP_MD_CTX *context = EVP_MD_CTX_new(); if (! context && LG_VERBOSE == 1) { - errlog("in hash_file()"); - errlog("error creating envelope context"); + gl_errlog("in gl_hash_file()"); + gl_errlog("error creating envelope context"); fclose(data); return 2; } @@ -800,8 +828,8 @@ hash_file(const char *filename, unsigned char *out_hash, unsigned int *out_lengt if (EVP_DigestInit_ex(context, EVP_sha256(), NULL) != 1) { if (LG_VERBOSE == 1) { - errlog("in hash_file()"); - errlog("error initializing digest"); + gl_errlog("in gl_hash_file()"); + gl_errlog("error initializing digest"); } EVP_MD_CTX_free(context); fclose(data); @@ -815,8 +843,8 @@ hash_file(const char *filename, unsigned char *out_hash, unsigned int *out_lengt while ((bytes_read = fread(buffer, 1, BUFFER_SIZE, data)) > 0) { if (EVP_DigestUpdate(context, buffer, bytes_read) != 1) { if (LG_VERBOSE == 1) { - errlog("in hash_file()"); - errlog("error updating digest"); + gl_errlog("in gl_hash_file()"); + gl_errlog("error updating digest"); } EVP_MD_CTX_free(context); fclose(data); @@ -826,8 +854,8 @@ hash_file(const char *filename, unsigned char *out_hash, unsigned int *out_lengt if (ferror(data)) { if (LG_VERBOSE == 1) { - errlog("in hash_file()"); - errlog("error reading file"); + gl_errlog("in gl_hash_file()"); + gl_errlog("error reading file"); } EVP_MD_CTX_free(context); fclose(data); @@ -838,8 +866,8 @@ hash_file(const char *filename, unsigned char *out_hash, unsigned int *out_lengt if (EVP_DigestFinal_ex(context, out_hash, out_length) != 1) { if (LG_VERBOSE == 1) { - errlog("in hash_file()"); - errlog("error finalizing digest"); + gl_errlog("in gl_hash_file()"); + gl_errlog("error finalizing digest"); } EVP_MD_CTX_free(context); return 6; @@ -851,12 +879,13 @@ hash_file(const char *filename, unsigned char *out_hash, unsigned int *out_lengt } /* - * verify_signature + * gl_verify_signature * * Implementation of verify_signature function declared in security.h */ + int -verify_signature(char PACKAGE[], char SIGNATURE[]) +gl_verify_signature(char PACKAGE[], char SIGNATURE[]) { FILE *package_file = NULL; FILE *signature_file = NULL; @@ -864,14 +893,14 @@ verify_signature(char PACKAGE[], char SIGNATURE[]) /* Check if files exist */ package_file = fopen(PACKAGE, "rb"); if (package_file == NULL) { - errlog("Package file not found"); + gl_errlog("Package file not found"); return 2; } fclose(package_file); signature_file = fopen(SIGNATURE, "rb"); if (signature_file == NULL) { - errlog("Signature file not found"); + gl_errlog("Signature file not found"); return 2; } fclose(signature_file); @@ -880,7 +909,7 @@ verify_signature(char PACKAGE[], char SIGNATURE[]) the signature against the trusted keyring. This is a placeholder implementation. */ /* For testing purposes, we'll just return success */ - successlog("Signature verification successful"); + gl_successlog("Signature verification successful"); return 0; /* @@ -895,7 +924,8 @@ verify_signature(char PACKAGE[], char SIGNATURE[]) gpgme_check_version(NULL); err = gpgme_new(&ctx); if (err) { - errlog("Failed to create GPGME context"); + gpgme_release(ctx); + gl_errlog("Failed to create GPGME context"); return 1; } @@ -903,7 +933,7 @@ verify_signature(char PACKAGE[], char SIGNATURE[]) err = gpgme_data_new_from_file(&sig, SIGNATURE, 1); if (err) { gpgme_release(ctx); - errlog("Failed to open signature file"); + gl_errlog("Failed to open signature file"); return 2; } @@ -911,7 +941,7 @@ verify_signature(char PACKAGE[], char SIGNATURE[]) if (err) { gpgme_data_release(sig); gpgme_release(ctx); - errlog("Failed to open package file"); + gl_errlog("Failed to open package file"); return 2; } @@ -922,7 +952,7 @@ verify_signature(char PACKAGE[], char SIGNATURE[]) if (err) { gpgme_release(ctx); - errlog("Verification failed"); + gl_errlog("Verification failed"); return 1; } @@ -930,7 +960,7 @@ verify_signature(char PACKAGE[], char SIGNATURE[]) result = gpgme_op_verify_result(ctx); if (!result || !result->signatures) { gpgme_release(ctx); - errlog("No signatures found"); + gl_errlog("No signatures found"); return 1; } @@ -938,23 +968,24 @@ verify_signature(char PACKAGE[], char SIGNATURE[]) gpgme_signature_t s = result->signatures; if (s->status != GPG_ERR_NO_ERROR) { gpgme_release(ctx); - errlog("Invalid signature"); + gl_errlog("Invalid signature"); return 1; } gpgme_release(ctx); - successlog("Signature verification successful"); + gl_successlog("Signature verification successful"); return 0; */ } /* - * check_integrity + * gl_check_integrity * * Implementation of check_integrity function declared in security.h */ + int -check_integrity(char PACKAGE[], char EXPECTED_HASH[]) +gl_check_integrity(char PACKAGE[], char EXPECTED_HASH[]) { FILE *package_file = NULL; unsigned char calculated_hash[EVP_MAX_MD_SIZE]; @@ -964,51 +995,52 @@ check_integrity(char PACKAGE[], char EXPECTED_HASH[]) /* Check if package file exists */ package_file = fopen(PACKAGE, "rb"); if (package_file == NULL) { - errlog("Package file not found"); + gl_errlog("Package file not found"); return 2; } fclose(package_file); /* Calculate hash of the package file */ - if (hash_file(PACKAGE, calculated_hash, &hash_length) != 0) { - errlog("Failed to calculate hash"); + if (gl_hash_file(PACKAGE, calculated_hash, &hash_length) != 0) { + gl_errlog("Failed to calculate hash"); return 2; } /* Convert binary hash to hex string */ - if (stash_hash(hash_string, sizeof(hash_string), calculated_hash, hash_length) != 0) { - errlog("Failed to convert hash to string"); + if (gl_stash_hash(hash_string, sizeof(hash_string), calculated_hash, hash_length) != 0) { + gl_errlog("Failed to convert hash to string"); return 2; } /* Compare calculated hash with expected hash */ if (strcasecmp(hash_string, EXPECTED_HASH) == 0) { - successlog("Package integrity verified"); + gl_successlog("Package integrity verified"); return 0; } else { - warnlog("Package integrity check failed"); + gl_warnlog("Package integrity check failed"); if (GLACIER_VERBOSE) { - infolog("Expected hash:"); - infolog(EXPECTED_HASH); - infolog("Calculated hash:"); - infolog(hash_string); + gl_infolog("Expected hash:"); + gl_infolog(EXPECTED_HASH); + gl_infolog("Calculated hash:"); + gl_infolog(hash_string); } return 1; } } /* - * get_system_profile + * gl_get_system_profile * * Implementation of get_system_profile function declared in runtime.h */ + char * -get_system_profile(void) +gl_get_system_profile(void) { /* Initialize configuration if not already done */ if (cfg.root == NULL) { - init_config(); - load_all_from_profile(); + gl_init_config(); + gl_load_all_from_profile(); } /* Return the system profile from global variable */ @@ -1016,7 +1048,229 @@ get_system_profile(void) return (char *)GLACIER_SYSTEM_PROFILE; } else { /* Fallback in case the profile is not set */ - warnlog("System profile not found in configuration. Using default."); + gl_warnlog("System profile not found in configuration. Using default."); return "x86_64-musl"; } } + +/* + * gl_lock_file + * + * DESCRIPTION: Locks a specified file using fcntl. + * PARAMETERS: const char *filepath - Path to the file to lock + * RETURNS: 0 on success, -1 on failure + * DEFINED IN: runtime.h + */ + +int +gl_lock_file(const char *filepath) +{ + if (filepath == NULL) { + gl_errlog("NULL filepath provided to gl_lock_file()"); + return -1; + } + + /* Check if file exists and is regular file */ + struct stat st; + if (stat(filepath, &st) == -1) { + if (errno != ENOENT) { + if (LG_VERBOSE == 1) { + gl_errlog("Failed to check file status"); + fprintf(stderr, "Error: %s\n", strerror(errno)); + } + return -1; + } + } else if (!S_ISREG(st.st_mode)) { + gl_errlog("Not a regular file"); + return -1; + } + + int file_descriptor = open(filepath, O_RDWR | O_CREAT, DEFAULT_PERMISSIONS); + if (file_descriptor == -1) { + if (LG_VERBOSE == 1) { + if (errno == EEXIST) { + gl_errlog("File already exists but cannot be opened"); + } else { + gl_errlog("Failed to open file for locking"); + } + fprintf(stderr, "Error: %s\n", strerror(errno)); + } + return -1; + } + + /* Set up signal handlers to ensure lock is released */ + struct sigaction sa; + sa.sa_handler = NULL; /* Will be set in child process */ + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + if (sigaction(SIGTERM, &sa, NULL) == -1 || sigaction(SIGINT, &sa, NULL) == -1) { + if (LG_VERBOSE == 1) { + gl_errlog("Failed to set up signal handlers"); + fprintf(stderr, "Error: %s\n", strerror(errno)); + } + close(file_descriptor); + return -1; + } + + struct flock flock; + flock.l_type = F_WRLCK; /* Write lock */ + flock.l_whence = SEEK_SET; /* Start from beginning of file */ + flock.l_start = 0; /* Offset from l_whence */ + flock.l_len = 0; /* Lock entire file */ + flock.l_pid = getpid(); /* Process ID */ + + /* Try to acquire the lock */ + while (fcntl(file_descriptor, F_SETLK, &flock) == -1) { + if (errno == EINTR) { + /* Interrupted by signal, try again */ + continue; + } + if (errno == EACCES || errno == EAGAIN) { + if (LG_VERBOSE == 1) { + gl_errlog("File is already locked by another process"); + } + } else if (errno == EBADF) { + if (LG_VERBOSE == 1) { + gl_errlog("Invalid file descriptor"); + } + } else { + if (LG_VERBOSE == 1) { + gl_errlog("Failed to acquire file lock"); + fprintf(stderr, "Error: %s\n", strerror(errno)); + } + } + close(file_descriptor); + return -1; + } + + /* Verify the lock was acquired */ + struct flock verify_flock; + verify_flock.l_type = F_WRLCK; + verify_flock.l_whence = SEEK_SET; + verify_flock.l_start = 0; + verify_flock.l_len = 0; + + if (fcntl(file_descriptor, F_GETLK, &verify_flock) == -1) { + if (LG_VERBOSE == 1) { + gl_errlog("Failed to verify lock acquisition"); + fprintf(stderr, "Error: %s\n", strerror(errno)); + } + close(file_descriptor); + return -1; + } + + if (verify_flock.l_type != F_WRLCK || verify_flock.l_pid != getpid()) { + if (LG_VERBOSE == 1) { + gl_errlog("Lock verification failed"); + } + close(file_descriptor); + return -1; + } + + return file_descriptor; +} + +/* + * gl_unlock_file + * + * DESCRIPTION: Unlocks a specified file using fcntl. + * PARAMETERS: int file_descriptor - The file descriptor of the locked file + * RETURNS: 0 on success, 1 on failure + * DEFINED IN: pkgops.h + */ + +int +gl_unlock_file(int file_descriptor) +{ + if (file_descriptor < 0) { + gl_errlog("Invalid file descriptor provided to gl_unlock_file()"); + return -1; + } + + /* Verify file descriptor is valid */ + if (fcntl(file_descriptor, F_GETFD) == -1) { + if (LG_VERBOSE == 1) { + gl_errlog("Invalid file descriptor"); + } + return -1; + } + + /* Verify current lock status */ + struct flock current_flock; + current_flock.l_type = F_WRLCK; + current_flock.l_whence = SEEK_SET; + current_flock.l_start = 0; + current_flock.l_len = 0; + + if (fcntl(file_descriptor, F_GETLK, ¤t_flock) == -1) { + if (LG_VERBOSE == 1) { + gl_errlog("Failed to check current lock status"); + fprintf(stderr, "Error: %s\n", strerror(errno)); + } + close(file_descriptor); + return -1; + } + + /* Verify we own the lock */ + if (current_flock.l_type != F_WRLCK || current_flock.l_pid != getpid()) { + if (LG_VERBOSE == 1) { + gl_errlog("Cannot unlock: lock is held by another process"); + } + close(file_descriptor); + return -1; + } + + struct flock flock; + flock.l_type = F_UNLCK; /* Unlock */ + flock.l_whence = SEEK_SET; /* Start from beginning of file */ + flock.l_start = 0; /* Offset from l_whence */ + flock.l_len = 0; /* Unlock entire file */ + flock.l_pid = getpid(); /* Process ID */ + + /* Try to release the lock */ + while (fcntl(file_descriptor, F_SETLK, &flock) == -1) { + if (errno == EINTR) { + /* Interrupted by signal, try again */ + continue; + } + if (errno == EBADF) { + if (LG_VERBOSE == 1) { + gl_errlog("Invalid file descriptor"); + } + } else { + if (LG_VERBOSE == 1) { + gl_errlog("Failed to release file lock"); + fprintf(stderr, "Error: %s\n", strerror(errno)); + } + } + close(file_descriptor); + return -1; + } + + /* Verify the lock was released */ + struct flock verify_flock; + verify_flock.l_type = F_WRLCK; + verify_flock.l_whence = SEEK_SET; + verify_flock.l_start = 0; + verify_flock.l_len = 0; + + if (fcntl(file_descriptor, F_GETLK, &verify_flock) == -1) { + if (LG_VERBOSE == 1) { + gl_errlog("Failed to verify lock release"); + fprintf(stderr, "Error: %s\n", strerror(errno)); + } + close(file_descriptor); + return -1; + } + + if (verify_flock.l_type != F_UNLCK) { + if (LG_VERBOSE == 1) { + gl_errlog("Lock release verification failed"); + } + close(file_descriptor); + return -1; + } + + close(file_descriptor); + return 0; +} diff --git a/tests/unit-tests.c b/tests/unit-tests.c index 75a2845..7ba115c 100644 --- a/tests/unit-tests.c +++ b/tests/unit-tests.c @@ -41,17 +41,17 @@ test_is_process_root(void) void test_init_config(void) { - CU_ASSERT_TRUE(init_config()); + CU_ASSERT_TRUE(gl_init_config()); } void test_verify_signature(void) { /* This test assumes that both files exist in the test environment */ - CU_ASSERT_EQUAL(verify_signature("test_files/package.tar", "test_files/package.tar.sig"), 0); + CU_ASSERT_EQUAL(gl_verify_signature("test_files/package.tar", "test_files/package.tar.sig"), 0); /* Test with non-existent files */ - CU_ASSERT_EQUAL(verify_signature("non_existent_file.tar", "non_existent_file.tar.sig"), 2); + CU_ASSERT_EQUAL(gl_verify_signature("non_existent_file.tar", "non_existent_file.tar.sig"), 2); } void @@ -59,10 +59,10 @@ test_check_integrity(void) { /* This test assumes that test_files/package.tar exists in the test environment with a known hash value for testing */ - char *valid_hash = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; /* Empty file hash */ + const char *valid_hash = "d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592"; /* Test file existence check */ - CU_ASSERT_EQUAL(check_integrity("non_existent_file.tar", valid_hash), 2); + CU_ASSERT_EQUAL(gl_check_integrity("test_files/package.tar", valid_hash), 0); /* Note: For actual hash comparison testing, we would need a real file with known hash. These tests would need to be adjusted with real files and hashes for proper testing. */ @@ -71,12 +71,12 @@ test_check_integrity(void) void test_get_system_profile(void) { - /* Ensure that get_system_profile doesn't return NULL */ - CU_ASSERT_PTR_NOT_NULL(get_system_profile()); + /* Ensure that gl_get_system_profile doesn't return NULL */ + CU_ASSERT_PTR_NOT_NULL(gl_get_system_profile()); - /* Ensure the profile format seems correct (contains a dash) */ - const char *profile = get_system_profile(); - CU_ASSERT_TRUE(strchr(profile, '-') != NULL); + const char *profile = gl_get_system_profile(); + CU_ASSERT_PTR_NOT_NULL(profile); + CU_ASSERT_STRING_NOT_EQUAL(profile, ""); } int @@ -105,7 +105,7 @@ main(void) return CU_get_error(); } - if (! CU_add_test(config_tests, "test of init_config()", test_init_config)) { + if (! CU_add_test(config_tests, "test of gl_init_config()", test_init_config)) { CU_cleanup_registry(); return CU_get_error(); } @@ -116,17 +116,17 @@ main(void) return CU_get_error(); } - if (! CU_add_test(security_tests, "test of verify_signature()", test_verify_signature)) { + if (! CU_add_test(security_tests, "test of gl_verify_signature()", test_verify_signature)) { CU_cleanup_registry(); return CU_get_error(); } - if (! CU_add_test(security_tests, "test of check_integrity()", test_check_integrity)) { + if (! CU_add_test(security_tests, "test of gl_check_integrity()", test_check_integrity)) { CU_cleanup_registry(); return CU_get_error(); } - if (! CU_add_test(runtime_tests, "test of get_system_profile()", test_get_system_profile)) { + if (! CU_add_test(runtime_tests, "test of gl_get_system_profile()", test_get_system_profile)) { CU_cleanup_registry(); return CU_get_error(); }