/* * Arguments: * pat Pointer to memory that will be set to point to an * allocated Pattern. Set on and only on success. * ere The extended regular expression. Caller may free upon * return. If the expression is a pathological * regular-expression, then it will be repaired. * ignoreCase Whether or not to ignore case in matches. * * Returns: * NULL Success. *pat is set. * else Error object. err_code() values: * 1 System error. *pat not set. * 2 Invalid ERE. *pat not set. */ ErrorObj* pat_new( Pattern** const pat, const char* const ere, const int ignoreCase) { ErrorObj* errObj = NULL; /* success */ int isTrivial = 0 == strcmp(".*", ere); if (isTrivial && NULL != matchAll) { *pat = matchAll; } else { Pattern* const ptr = (Pattern*)malloc(sizeof(Pattern)); if (NULL == ptr) { errObj = ERR_NEW2(1, NULL, "Couldn't allocate %lu bytes: %s", (unsigned long)sizeof(Pattern), strerror(errno)); } else { ptr->string = strdup(ere); if (NULL == ptr->string) { errObj = ERR_NEW2(1, NULL, "Couldn't copy string \"%s\": %s", ere, strerror(errno)); } else { int err; (void)re_vetSpec(ptr->string); if (err = regcomp(&ptr->reg, ptr->string, REG_EXTENDED | REG_NOSUB | (ignoreCase ? REG_ICASE : 0))) { char buf[512]; (void)regerror(err, &ptr->reg, buf, sizeof(buf)); errObj = ERR_NEW2((REG_ESPACE == err) ? 1 : 2, NULL, "Couldn't compile ERE \"%s\": %s", ptr->string, buf); } else { ptr->ignoreCase = ignoreCase; *pat = ptr; if (isTrivial && NULL == matchAll) matchAll = ptr; } /* ERE compiled */ if (errObj) free(ptr->string); } /* ptr->string allocated */ if (errObj) free(ptr); } /* "ptr" allocated */ } /* non-trivial ERE or matchAll==NULL */ return errObj; }
/* * Returns a new upstream filter. * * Arguments: * upFilter Pointer to pointer to returned upstream filter. Must * not be NULL. Set on and only on success. * Returns: * NULL Success. * else Failure error object. */ ErrorObj* upFilter_new( UpFilter** const upFilter) { ErrorObj* errObj; size_t nbytes = sizeof(UpFilter); UpFilter* const filt = (UpFilter*)malloc(nbytes); if (NULL == filt) { errObj = ERR_NEW2(0, NULL, "Couldn't allocate %lu-bytes: %s", (unsigned long)nbytes, strerror(errno)); } else { StringBuf* const strBuf = strBuf_new(132); if (NULL == strBuf) { errObj = ERR_NEW(0, NULL, strBuf_strerror(strBuf)); free(filt); } else { filt->strBuf = strBuf; filt->head = NULL; filt->stringOutOfDate = 1; filt->count = 0; *upFilter = filt; errObj = NULL; /* success */ } } /* "filt" allocated */ return errObj; }
/* * Opens a shared-counter. * * Arguments: * path Pathname of the stat()able file to be associated with * the shared-counter. * *sc Pointer to shared-counter. Set on and only on success. * * Returns: * NULL Success * !NULL Failure: * SC_SYSTEM */ ErrorObj* sc_open( const char* path, SharedCounter** const sc) { ErrorObj* error; size_t nbytes = sizeof(SharedCounter); SharedCounter* ptr = malloc(nbytes); if (NULL == ptr) { error = ERR_NEW2(SC_SYSTEM, NULL, "Couldn't allocate %lu bytes: %s", (unsigned long)nbytes, strerror(errno)); } else { key_t key = ftok(path, 0); if ((key_t)-1 == key) { error = ERR_NEW1(SC_SYSTEM, NULL, "Couldn't create key for shared-memory segment: %s", strerror(errno)); } else { int shmid = shmget(key, sizeof(unsigned), 0600 | IPC_CREAT); if (-1 == shmid) { error = ERR_NEW1(SC_SYSTEM, NULL, "Couldn't get shared-memory segment: %s", strerror(errno)); } else { void* const counter = shmat(shmid, NULL, 0); if ((void*)-1 == counter) { error = ERR_NEW1(SC_SYSTEM, NULL, "Couldn't attach shared-memory segment: %s", strerror(errno)); } else { ptr->shmid = shmid; ptr->counter = (unsigned*)counter; *sc = ptr; error = NULL; /* success */ } /* shared-memory segment attached */ if (error) (void)shmctl(shmid, IPC_RMID, NULL); } /* got shared-memory segment */ } /* got key for shared memory segment */ if (error) free(ptr); } /* ptr allocated */ return error; }
/* * Decodes a data-product signature from the last product-specification of a * product-class if it exists. * * Arguments: * class Pointer to the product-class. Caller may free upon * return. * Returns: * NULL The last product-specification didn't contain a valid, * encoded signature. * else Pointer to a static signature buffer into which the * signature specification was successfully decoded. */ static const signaturet* decodeSignature( const prod_class_t* const prodClass) { const signaturet* sig = NULL; /* no valid, encoded signature */ if (0 < prodClass->psa.psa_len) { const prod_spec* const lastProdSpec = &prodClass->psa.psa_val[prodClass->psa.psa_len - 1]; if (NONE == lastProdSpec->feedtype) { char* pat = lastProdSpec->pattern; if (strncasecmp("SIG=", pat, 4) == 0) { char* encodedSig = pat + 4; int i; unsigned value; static signaturet sigBuf; errno = 0; for (i = 0; i < sizeof(signaturet); i++) { if (sscanf(encodedSig + 2 * i, "%2x", &value) != 1) break; sigBuf[i] = (unsigned char) value; } if (i == sizeof(signaturet)) { sig = (const signaturet*) &sigBuf[0]; } else { if (0 == errno) { err_log_and_free( ERR_NEW1(1, NULL, "Invalid signature (%s)", encodedSig), ERR_NOTICE); } else { err_log_and_free( ERR_NEW2(1, NULL, "Invalid signature (%s): %s", encodedSig, strerror(errno)), ERR_NOTICE); } } /* signature not decoded */ } /* "SIG=" found */ } /* last feedtype is NONE */ } /* at least one product-specification */ return sig; }
/* * Attempts to connect to an upstream LDM using a range of LDM versions. The * versions are tried, in order, from highest to lowest. This function returns * on the first successful attempt. If the host is unknown or the RPC call * times-out, then the version-loop is prematurely terminated and this function * returns immediately. * * The client is responsible for freeing the client resources set by this * function on success. Calls exitIfDone() after potentially lengthy * operations. * * Arguments: * upName The name of the upstream LDM host. * port The port on which to connect. * version Program version. * *client Pointer to CLIENT structure. Set on success. * *socket The socket used for the connection. May be NULL. * *upAddr The IP address of the upstream LDM host. Set on * success. May be NULL. * Returns: * NULL Success. *vers_out, *client, *sock_out, and *upAddr * set. * !NULL Error. "*client" is not set. err_code(RETURN_VALUE): * LDM_CLNT_UNKNOWN_HOST Unknown upstream host. * LDM_CLNT_TIMED_OUT Call to upstream host timed-out. * LDM_CLNT_BAD_VERSION Upstream LDM isn't given version. * LDM_CLNT_NO_CONNECT Other connection-related error. * LDM_CLNT_SYSTEM_ERROR A fatal system-error occurred. */ ErrorObj* ldm_clnttcp_create_vers( const char* const upName, const unsigned port, unsigned const version, CLIENT** const client, int* const socket, struct sockaddr_in* upAddr) { ErrorObj* error; struct sockaddr_in addr; log_assert(upName != NULL); log_assert(client != NULL); /* * Get the IP address of the upstream LDM. This is a potentially * lengthy operation. */ (void)exitIfDone(0); error = ldm_clnt_addr(upName, &addr); if (error) { error = ERR_NEW1(LDM_CLNT_UNKNOWN_HOST, error, "Couldn't get IP address of host %s", upName); } else { int sock; int errCode; CLIENT* clnt = NULL; /* * Connect to the remote port. This is a potentially lengthy * operation. */ (void)exitIfDone(0); error = ldm_clnt_tcp_create(&addr, version, port, &clnt, &sock); if (error) { errCode = err_code(error); if (LDM_CLNT_NO_CONNECT != errCode) { error = ERR_NEW3(errCode, error, "Couldn't connect to LDM %d on %s " "using port %d", version, upName, port); } else { err_log_and_free( ERR_NEW3(0, error, "Couldn't connect to LDM %d on %s using port " "%d", version, upName, port), ERR_INFO); /* * Connect using the portmapper. This is a * potentially lengthy operation. */ (void)exitIfDone(0); error = ldm_clnt_tcp_create(&addr, version, 0, &clnt, &sock); if (error) { error = ERR_NEW2(err_code(error), error, "Couldn't connect to LDM on %s " "using either port %d or portmapper", upName, port); } /* portmapper failure */ } /* non-fatal port failure */ } /* port failure */ if (!error) { /* * Success. Set the return arguments. */ *client = clnt; if (socket) *socket = sock; if (upAddr) *upAddr = addr; } } /* got upstream IP address */ return error; }
hiya_reply_t* hiya_6_svc( prod_class_t *offered, struct svc_req *rqstp) { const char* const pqfname = getQueuePath(); static hiya_reply_t reply; SVCXPRT * const xprt = rqstp->rq_xprt; struct sockaddr_in *upAddr = (struct sockaddr_in*) svc_getcaller(xprt); const char *upName = hostbyaddr(upAddr); int error; int isPrimary; unsigned int maxHereis; static prod_class_t *accept; /* * Open the product-queue for writing. It will be closed by cleanup() * during process termination. */ if (pq) { (void) pq_close(pq); pq = NULL; } error = pq_open(pqfname, PQ_DEFAULT, &pq); if (error) { err_log_and_free(ERR_NEW2(error, NULL, "Couldn't open product-queue \"%s\" for writing: %s", pqfname, PQ_CORRUPT == error ? "The product-queue is inconsistent" : strerror(error)), ERR_FAILURE); svcerr_systemerr(xprt); svc_destroy(xprt); exit(error); } /* else */ error = down6_init(upName, upAddr, pqfname, pq); if (error) { uerror("Couldn't initialize downstream LDM"); svcerr_systemerr(xprt); svc_destroy(xprt); exit(error); } else { uinfo("Downstream LDM initialized"); } /* * The previous "accept" is freed here -- rather than freeing the * soon-to-be-allocated "accept" at the end of its block -- because it can * be used in the reply. */ if (accept) { free_prod_class(accept); /* NULL safe */ accept = NULL; } error = lcf_reduceToAcceptable(upName, inet_ntoa(upAddr->sin_addr), offered, &accept, &isPrimary); maxHereis = isPrimary ? UINT_MAX : 0; if (error) { serror("Couldn't validate HIYA"); svcerr_systemerr(xprt); svc_destroy(xprt); exit(error); } else { if (ulogIsDebug()) udebug("intersection: %s", s_prod_class(NULL, 0, accept)); if (accept->psa.psa_len == 0) { uwarn("Empty intersection of HIYA offer from %s (%s) and ACCEPT " "entries", upName, s_prod_class(NULL, 0, offered)); svcerr_weakauth(xprt); svc_destroy(xprt); exit(0); } else { error = down6_set_prod_class(accept); if (error) { if (DOWN6_SYSTEM_ERROR == error) { serror("Couldn't set product class: %s", s_prod_class(NULL, 0, accept)); } else { uerror("Couldn't set product class: %s", s_prod_class(NULL, 0, accept)); } svcerr_systemerr(xprt); svc_destroy(xprt); exit(EXIT_FAILURE); } /* else */ if (clss_eq(offered, accept)) { unotice("hiya6: %s", s_prod_class(NULL, 0, offered)); reply.code = OK; reply.hiya_reply_t_u.max_hereis = maxHereis; } else { if (ulogIsVerbose()) { char off[512]; char acc[512]; (void) s_prod_class(off, sizeof(off), offered), (void) s_prod_class( acc, sizeof(acc), accept); uinfo("hiya6: RECLASS: %s -> %s", off, acc); } reply.code = RECLASS; reply.hiya_reply_t_u.feedPar.prod_class = accept; reply.hiya_reply_t_u.feedPar.max_hereis = maxHereis; } } /* product-intersection != empty set */ } /* successful acl_check_hiya() */ return &reply; }
/* * Adds a filter-component to an upstream-filter. * * Arguments: * upFilter Pointer to the upstream-filter to which to add the * component. * feedtype The feedtype of the filter-component. * okPattern Pointer to the "OK pattern" of the filter-component to * be added. Caller may free upon return. * notPattern Pointer to the "not pattern" of the filter-component to * be added. May be NULL to indicate that such matching * should be disabled. Caller may free upon return. * Returns: * NULL Success. * else Error object. */ ErrorObj* upFilter_addComponent( UpFilter* const upFilter, const feedtypet feedtype, const Pattern* const okPattern, const Pattern* const notPattern) { ErrorObj* errObj = NULL; /* success */ Element* elt; /* * Ensure that the given feedtype is disjoint from all feedtypes already * in the filter. */ for (elt = upFilter->head; NULL != elt; elt = elt->next) { if (feedtype & elt->ft) { char ftSpec[512]; (void)sprint_feedtypet(ftSpec, sizeof(ftSpec), feedtype); errObj = ERR_NEW2(0, NULL, "Feedtype %s overlaps with feedtype %s", ftSpec, s_feedtypet(elt->ft)); break; } } if (NULL == errObj) { size_t nbytes = sizeof(Element); elt = (Element*)malloc(nbytes); if (NULL == elt) { errObj = ERR_NEW2(0, NULL, "Couldn't allocate %lu-bytes: %s", (unsigned long)nbytes, strerror(errno)); } else { if ((errObj = pat_clone(&elt->okPattern, okPattern))) { errObj = ERR_NEW(0, errObj, "Couldn't clone \"OK\" pattern"); free(elt); } else { if (NULL == notPattern) { elt->notPattern = NULL; } else { if ((errObj = pat_clone(&elt->notPattern, notPattern))) { errObj = ERR_NEW(0, errObj, "Couldn't clone \"not\" pattern"); pat_free(elt->okPattern); free(elt); elt = NULL; } } if (elt) { elt->ft = feedtype; elt->next = upFilter->head; upFilter->head = elt; upFilter->stringOutOfDate = 1; upFilter->count++; } } /* "elt->okPattern" allocated */ } /* "elt" allocated */ } // given feedtype is disjoint from those already in filter return errObj; }