/** Log to thread local error buffer * * @param fmt printf style format string. If NULL sets the 'new' byte to false, * effectively clearing the last message. */ void fr_strerror_printf(char const *fmt, ...) { va_list ap; char *buffer; buffer = fr_thread_local_init(fr_strerror_buffer, _fr_logging_free); if (!buffer) { int ret; /* * malloc is thread safe, talloc is not */ buffer = calloc((FR_STRERROR_BUFSIZE * 2) + 1, sizeof(char)); /* One byte extra for status */ if (!buffer) { fr_perror("Failed allocating memory for libradius error buffer"); return; } ret = fr_thread_local_set(fr_strerror_buffer, buffer); if (ret != 0) { fr_perror("Failed setting up thread-local storage for libradius error buffer: %s", fr_syserror(ret)); free(buffer); return; } } /* * NULL has a special meaning, setting the new bit to false. */ if (!fmt) { buffer[FR_STRERROR_BUFSIZE * 2] &= 0x06; return; } va_start(ap, fmt); /* * Alternate where we write the message, so we can do: * fr_strerror_printf("Additional error: %s", fr_strerror()); */ switch (buffer[FR_STRERROR_BUFSIZE * 2] & 0x06) { default: vsnprintf(buffer + FR_STRERROR_BUFSIZE, FR_STRERROR_BUFSIZE, fmt, ap); buffer[FR_STRERROR_BUFSIZE * 2] = 0x05; /* Flip the 'new' bit to true */ break; case 0x04: vsnprintf(buffer, FR_STRERROR_BUFSIZE, fmt, ap); buffer[FR_STRERROR_BUFSIZE * 2] = 0x03; /* Flip the 'new' bit to true */ break; } va_end(ap); }
char const *rlm_krb5_error(krb5_context context, krb5_error_code code) { char const *msg; char *buffer; buffer = fr_thread_local_init(krb5_error_buffer, _krb5_logging_free); if (!buffer) { int ret; /* * malloc is thread safe, talloc is not */ buffer = malloc(sizeof(char) * KRB5_STRERROR_BUFSIZE); if (!buffer) { ERROR("Failed allocating memory for krb5 error buffer"); return NULL; } ret = fr_thread_local_set(krb5_error_buffer, buffer); if (ret != 0) { ERROR("Failed setting up TLS for krb5 error buffer: %s", fr_syserror(ret)); free(buffer); return NULL; } } msg = krb5_get_error_message(context, code); if (msg) { strlcpy(buffer, msg, KRB5_STRERROR_BUFSIZE); # ifdef HAVE_KRB5_FREE_ERROR_MESSAGE krb5_free_error_message(context, msg); # elif defined(HAVE_KRB5_FREE_ERROR_STRING) { char *free; memcpy(&free, &msg, sizeof(free)); krb5_free_error_string(context, free); } # else # error "No way to free error strings, missing krb5_free_error_message() and krb5_free_error_string()" # endif } else { strlcpy(buffer, "Unknown error", KRB5_STRERROR_BUFSIZE); } return buffer; }
/** Log to thread local error buffer * * @param fmt printf style format string. If NULL sets the 'new' byte to false, * effectively clearing the last message. */ void fr_strerror_printf(char const *fmt, ...) { va_list ap; char *buffer; buffer = fr_thread_local_init(fr_strerror_buffer, _fr_logging_free); if (!buffer) { int ret; /* * malloc is thread safe, talloc is not */ buffer = malloc(sizeof(char) * (FR_STRERROR_BUFSIZE + 1)); /* One byte extra for status */ if (!buffer) { fr_perror("Failed allocating memory for libradius error buffer"); return; } ret = fr_thread_local_set(fr_strerror_buffer, buffer); if (ret != 0) { fr_perror("Failed setting up TLS for libradius error buffer: %s", fr_syserror(ret)); free(buffer); return; } } /* * NULL has a special meaning, setting the new byte to false. */ if (!fmt) { buffer[FR_STRERROR_BUFSIZE] = '\0'; return; } va_start(ap, fmt); vsnprintf(buffer, FR_STRERROR_BUFSIZE, fmt, ap); buffer[FR_STRERROR_BUFSIZE] = '\1'; /* Flip the 'new' byte to true */ va_end(ap); }
static rlm_rcode_t do_python(rlm_python_t *inst, REQUEST *request, PyObject *pFunc, char const *funcname, bool worker) { vp_cursor_t cursor; VALUE_PAIR *vp; PyObject *pRet = NULL; PyObject *pArgs = NULL; int tuplelen; int ret; PyGILState_STATE gstate; PyThreadState *prev_thread_state = NULL; /* -Wuninitialized */ memset(&gstate, 0, sizeof(gstate)); /* -Wuninitialized */ /* Return with "OK, continue" if the function is not defined. */ if (!pFunc) return RLM_MODULE_NOOP; #ifdef HAVE_PTHREAD_H gstate = PyGILState_Ensure(); if (worker) { PyThreadState *my_thread_state; my_thread_state = fr_thread_local_init(local_thread_state, do_python_cleanup); if (!my_thread_state) { my_thread_state = PyThreadState_New(inst->main_thread_state->interp); if (!my_thread_state) { REDEBUG("Failed initialising local PyThreadState on first run"); PyGILState_Release(gstate); return RLM_MODULE_FAIL; } ret = fr_thread_local_set(local_thread_state, my_thread_state); if (ret != 0) { REDEBUG("Failed storing PyThreadState in TLS: %s", fr_syserror(ret)); PyThreadState_Clear(my_thread_state); PyThreadState_Delete(my_thread_state); PyGILState_Release(gstate); return RLM_MODULE_FAIL; } } prev_thread_state = PyThreadState_Swap(my_thread_state); /* Swap in our local thread state */ } #endif /* Default return value is "OK, continue" */ ret = RLM_MODULE_OK; /* * We will pass a tuple containing (name, value) tuples * We can safely use the Python function to build up a * tuple, since the tuple is not used elsewhere. * * Determine the size of our tuple by walking through the packet. * If request is NULL, pass None. */ tuplelen = 0; if (request != NULL) { for (vp = paircursor(&cursor, &request->packet->vps); vp; vp = pairnext(&cursor)) { tuplelen++; } } if (tuplelen == 0) { Py_INCREF(Py_None); pArgs = Py_None; } else { int i = 0; if ((pArgs = PyTuple_New(tuplelen)) == NULL) { ret = RLM_MODULE_FAIL; goto finish; } for (vp = paircursor(&cursor, &request->packet->vps); vp; vp = pairnext(&cursor), i++) { PyObject *pPair; /* The inside tuple has two only: */ if ((pPair = PyTuple_New(2)) == NULL) { ret = RLM_MODULE_FAIL; goto finish; } if (mod_populate_vptuple(pPair, vp) == 0) { /* Put the tuple inside the container */ PyTuple_SET_ITEM(pArgs, i, pPair); } else { Py_INCREF(Py_None); PyTuple_SET_ITEM(pArgs, i, Py_None); Py_DECREF(pPair); } } } /* Call Python function. */ pRet = PyObject_CallFunctionObjArgs(pFunc, pArgs, NULL); if (!pRet) { ret = RLM_MODULE_FAIL; goto finish; } if (!request) goto finish; /* * The function returns either: * 1. (returnvalue, replyTuple, configTuple), where * - returnvalue is one of the constants RLM_* * - replyTuple and configTuple are tuples of string * tuples of size 2 * * 2. the function return value alone * * 3. None - default return value is set * * xxx This code is messy! */ if (PyTuple_CheckExact(pRet)) { PyObject *pTupleInt; if (PyTuple_GET_SIZE(pRet) != 3) { ERROR("rlm_python:%s: tuple must be (return, replyTuple, configTuple)", funcname); ret = RLM_MODULE_FAIL; goto finish; } pTupleInt = PyTuple_GET_ITEM(pRet, 0); if (!PyInt_CheckExact(pTupleInt)) { ERROR("rlm_python:%s: first tuple element not an integer", funcname); ret = RLM_MODULE_FAIL; goto finish; } /* Now have the return value */ ret = PyInt_AsLong(pTupleInt); /* Reply item tuple */ mod_vptuple(request->reply, &request->reply->vps, PyTuple_GET_ITEM(pRet, 1), funcname); /* Config item tuple */ mod_vptuple(request, &request->config_items, PyTuple_GET_ITEM(pRet, 2), funcname); } else if (PyInt_CheckExact(pRet)) { /* Just an integer */ ret = PyInt_AsLong(pRet); } else if (pRet == Py_None) { /* returned 'None', return value defaults to "OK, continue." */ ret = RLM_MODULE_OK; } else { /* Not tuple or None */ ERROR("rlm_python:%s: function did not return a tuple or None", funcname); ret = RLM_MODULE_FAIL; goto finish; } finish: if (pArgs) { Py_DECREF(pArgs); } if (pRet) { Py_DECREF(pRet); } #ifdef HAVE_PTHREAD_H if (worker) { PyThreadState_Swap(prev_thread_state); } PyGILState_Release(gstate); #endif return ret; }
/** Guaranteed to be thread-safe version of strerror * * @param num errno as returned by function or from global errno. * @return local specific error string relating to errno. */ char const *fr_syserror(int num) { char *buffer, *p, *end; int ret; buffer = fr_thread_local_init(fr_syserror_buffer, _fr_logging_free); if (!buffer) { /* * malloc is thread safe, talloc is not */ buffer = malloc(sizeof(char) * FR_STRERROR_BUFSIZE); if (!buffer) { fr_perror("Failed allocating memory for system error buffer"); return NULL; } ret = fr_thread_local_set(fr_syserror_buffer, buffer); if (ret != 0) { fr_perror("Failed setting up thread-local storage for system error buffer"); free(buffer); return NULL; } } if (!num) return "No error"; p = buffer; end = p + FR_STRERROR_BUFSIZE; #ifndef NDEBUG /* * Prefix system errors with the macro name and number * if we're debugging. */ if (num < (int)(sizeof(fr_errno_macro_names) / sizeof(*fr_errno_macro_names))) { p += snprintf(p, end - p, "%s: ", fr_errno_macro_names[num]); } else { p += snprintf(p, end - p, "errno %i: ", num); } if (p >= end) return p; #endif /* * XSI-Compliant version */ #if !defined(HAVE_FEATURES_H) || !defined(__GLIBC__) || ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 500) && ! _GNU_SOURCE) ret = strerror_r(num, p, end - p); if (ret != 0) { # ifndef NDEBUG fprintf(stderr, "strerror_r() failed to write error for errno %i to buffer %p (%zu bytes), " "returned %i: %s\n", num, buffer, (size_t) FR_STRERROR_BUFSIZE, ret, strerror(ret)); # endif buffer[0] = '\0'; } return buffer; /* * GNU Specific version * * The GNU Specific version returns a char pointer. That pointer may point * the buffer you just passed in, or to an immutable static string. */ #else { p = strerror_r(num, p, end - p); if (!p) { # ifndef NDEBUG fprintf(stderr, "strerror_r() failed to write error for errno %i to buffer %p " "(%zu bytes): %s\n", num, buffer, (size_t) FR_STRERROR_BUFSIZE, strerror(errno)); # endif buffer[0] = '\0'; return buffer; } return p; } #endif }
/** Guaranteed to be thread-safe version of strerror * * @param num errno as returned by function or from global errno. * @return local specific error string relating to errno. */ char const *fr_syserror(int num) { char *buffer; int ret; buffer = fr_thread_local_init(fr_syserror_buffer, _fr_logging_free); if (!buffer) { /* * malloc is thread safe, talloc is not */ buffer = malloc(sizeof(char) * FR_STRERROR_BUFSIZE); if (!buffer) { fr_perror("Failed allocating memory for system error buffer"); return NULL; } ret = fr_thread_local_set(fr_syserror_buffer, buffer); if (ret != 0) { fr_perror("Failed setting up TLS for system error buffer: %s", fr_syserror(ret)); free(buffer); return NULL; } } if (!num) { return "No error"; } /* * XSI-Compliant version */ #if !defined(HAVE_FEATURES_H) || ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 500) && ! _GNU_SOURCE) if ((ret = strerror_r(num, buffer, (size_t) FR_STRERROR_BUFSIZE) != 0)) { # ifndef NDEBUG fprintf(stderr, "strerror_r() failed to write error for errno %i to buffer %p (%zu bytes), " "returned %i: %s\n", num, buffer, (size_t) FR_STRERROR_BUFSIZE, ret, strerror(ret)); # endif buffer[0] = '\0'; } return buffer; /* * GNU Specific version * * The GNU Specific version returns a char pointer. That pointer may point * the buffer you just passed in, or to an immutable static string. */ #else { char const *p; p = strerror_r(num, buffer, (size_t) FR_STRERROR_BUFSIZE); if (!p) { # ifndef NDEBUG fprintf(stderr, "strerror_r() failed to write error for errno %i to buffer %p " "(%zu bytes): %s\n", num, buffer, (size_t) FR_STRERROR_BUFSIZE, strerror(errno)); # endif buffer[0] = '\0'; return buffer; } return p; } #endif }