Warning: Allocation result must be checked for NULL before use to prevent null pointer dereference.
auth_data = calloc(1, sb.st_size + 2);
1/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */2#include <stdio.h>3#include <stdlib.h>4#include <stdbool.h>5#include <string.h>6#include <sys/types.h>7#include <sys/stat.h>8#include <unistd.h>9#include <inttypes.h>10#include <pthread.h>1112#include "authfile.h"13#include "util.h"1415// TODO: frontend needs a refactor so this can avoid global objects.1617#define MAX_ENTRY_LEN 25618// Not supposed to be a huge database!19#define MAX_ENTRIES 82021typedef struct auth_entry {22 char *user;23 size_t ulen;24 char *pass;25 size_t plen;26} auth_t;2728auth_t main_auth_entries[MAX_ENTRIES];29int entry_cnt = 0;30char *main_auth_data = NULL;31pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;3233enum authfile_ret authfile_load(const char *file) {34 struct stat sb;35 char *auth_data = NULL;36 auth_t auth_entries[MAX_ENTRIES];3738 if (!file || strlen(file) == 0) {39 return AUTHFILE_OPENFAIL;40 }4142 FILE *pwfile = fopen(file, "r");43 if (pwfile == NULL) {44 return AUTHFILE_OPENFAIL;45 } else if (fstat(fileno(pwfile), &sb)) {46 fclose(pwfile);47 return AUTHFILE_STATFAIL;48 }4950 auth_data = calloc(1, sb.st_size + 2);5152 char *auth_cur = auth_data;53 // fgets will stop at EOF or a newline, reading at most one bytes less54 // than the size limit. If a user supplies a file without an ending55 // newline we will end up chopping the last character of the password.56 char *auth_end = auth_data + sb.st_size + 1;57 auth_t *entry_cur = auth_entries;58 int used = 0;5960 while ((fgets(auth_cur, auth_end - auth_cur < MAX_ENTRY_LEN ? auth_end - auth_cur : MAX_ENTRY_LEN, pwfile)) != NULL) {61 int x;62 int found = 0;6364 for (x = 0; x < MAX_ENTRY_LEN; x++) {65 if (!found) {66 if (auth_cur[x] == '\0') {67 // The username is malformed - this is either the end of the file or a null byte.68 break;69 } else if (auth_cur[x] == ':') {70 entry_cur->user = auth_cur;71 entry_cur->ulen = x;72 entry_cur->pass = &auth_cur[x+1];73 found = 1;74 }75 } else {76 // Find end of password.77 if (auth_cur[x] == '\n' ||78 auth_cur[x] == '\r' ||79 auth_cur[x] == '\0') {80 entry_cur->plen = x - (entry_cur->ulen + 1);81 break;82 }83 }84 }8586 // malformed line.87 if (!found) {88 (void)fclose(pwfile);89 free(auth_data);90 return AUTHFILE_MALFORMED;91 }9293 // FIXME: no silent truncation.94 if (++used == MAX_ENTRIES) {95 break;96 }97 // EOF98 if (auth_cur[x] == '\0')99 break;100101 auth_cur += x;102 entry_cur++;103 }104105 pthread_mutex_lock(&lock);106 // swap the main pointer out now, so if there's an error reloading we107 // don't break the existing authentication.108 if (main_auth_data != NULL) {109 free(main_auth_data);110 }111112 entry_cnt = used;113 main_auth_data = auth_data;114 memcpy(main_auth_entries, auth_entries, sizeof(auth_entries));115 pthread_mutex_unlock(&lock);116117 (void)fclose(pwfile);118119 return AUTHFILE_OK;120}121122// if only loading the file could be this short...123int authfile_check(const char *user, unsigned int ulen, const char *pass, unsigned int plen) {124 int ret = 0;125126 pthread_mutex_lock(&lock);127 for (int x = 0; x < entry_cnt; x++) {128 auth_t *e = &main_auth_entries[x];129 if (ulen == e->ulen && plen == e->plen &&130 safe_memcmp(user, e->user, e->ulen) &&131 safe_memcmp(pass, e->pass, e->plen)) {132 ret = 1;133 break;134 }135 }136 pthread_mutex_unlock(&lock);137138 return ret;139}
Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.