/* * DREADERD/DNS.C - dns resolution and authentication task * * DNS authenticator for new connections. * * (c)Copyright 1998, Matthew Dillon, All Rights Reserved. Refer to * the COPYRIGHT file in the base directory of this distribution * for specific rights granted. */ #include "defs.h" #ifdef LDAP_ENABLED #define LDAP_COMPARE #include #include #endif #ifdef DB_ENABLED #include #endif #ifdef PERL_ENABLED #include #include #endif Prototype void DnsTask(int fd, const char *id); Prototype void InstallAccessCache(void); Prototype int ReadAccessCache(void); Prototype void UpdateAuthDetails(ForkDesc *desc); Prototype void SetAuthDetails(DnsRes *dres, char *which); Prototype void PrintAuthDetails(DnsRes *dres); Prototype void ClearOldAccessMap(void); void DnsTest(DnsReq *dreq, DnsRes *dres, char *fqdn, char **ary, const char *ipname); void getAuthUser(const struct sockaddr *lsin, const struct sockaddr *rsin, char *ubuf, int ulen); int readExactly(int fd, void *buf, int bytes); void sigSegVDNS(int sigNo); int readtoeof(int fd, void *buf, int bytes, int secs); int readAccessLine(FILE *af, char *fname, AccessDef *adef); int xread(int fd, char *buf, int siz); void getRateLimitCmds(char *opt, ReaderDef *rd); /* * The various authentication methods * * The current interface to the authentication methods is the passing * of 3 strings as the parms: user, passwd, conf string from authdef * Returns a string: * NULL = failed * 100 Success - use readerdef from access file * 110 readerdef = Use this readerdef (unimplemented) */ char *fileAuthenticate(char *user, char *pass, char *conf); #ifdef RADIUS_ENABLED char *radiusAuthenticate(char *user, char *pass, char *conf); #endif #ifdef CDB_ENABLED extern int cdb_seek(int, char*, unsigned int, unsigned int*); char *cdbAuthenticate(char *user, char *pass, char *conf); #endif #ifdef DB_ENABLED char *dbAuthenticate(char *user, char *pass, char *conf); #endif #ifdef NETREMOTE_ENABLED void netRemoteAccounting(DnsReq *dreq); char *netRemoteAuthenticate(char *user, char *pass, char *conf, char *localip); #endif #ifdef LDAP_ENABLED #ifdef NEW_LDAP char * LDAPAuthenticate(char *user, char *pass, char *realm, char *conf); #else char * LDAPAuthenticate(char *user, char *pass, char *conf); #endif #endif /* LDAP_ENABLED */ #ifdef PERL_ENABLED char * PerlAuthenticate(char *user, char *pass, char *conf); #endif #ifdef PAM_ENABLED #include char *PamAuthenticate(char *user, char *pass, char *conf); #endif int DFd = -1; MemPool *DnsMemPool; time_t Access_LastUpdate = 0; time_t Cache_LastUpdate = 0; AccessMap accessmap; AccessMap oldaccessmap; /* -------------------------------------------------------------------*/ /* * This is the process that loops handling DNS and authentication requests * * It listens in a UNIX SOCKET for a dreq structure and responds with a * dres structure. * */ void DnsTask(int fd, const char *id) { /* * read remote address to resolve. Note: fd is not set to non-blocking */ DnsReq dreq; int n; DFd = fd; if (CoreDebugOpt) signal(SIGSEGV, sigSegVDNS); /* * Make dummy call to lock buffer so we do not inefficiently free and * reallocate it for every DNS request. */ (void)zalloc(&DnsMemPool, 8); /* * Loop on DNS requests, resolve them, and respond. */ while ((n = readExactly(fd, &dreq, sizeof(dreq))) == sizeof(dreq)) { DnsRes dres; bzero(&dres, sizeof(dres)); stprintf("reverse auth %s", NetAddrToSt(0, (struct sockaddr *)&dreq.dr_RSin, 1, 0, 1)); if (ReadAccessCache() == 1) ClearOldAccessMap(); if (dreq.dr_ResultFlags == DR_SESSEXIT_RPT) { /* * This handles session termination reporting, from a * dreaderd NNTP thread. The idea is to allow one of the * authentication methods to get information upon the * termination of a session. Currently, most auth methods * do not support this - NetRemote does. JG200106061320 * * Note that this all requires some additional work anyways */ dres.dr_ResultFlags = DR_SESSEXIT_RPT; #ifdef NETREMOTE_ENABLED if (*dreq.dr_AuthUser && *dreq.dr_AuthPass) { netRemoteAccounting(&dreq); } #endif } else { /* * This handles both initial connect and AUTHINFO stuff * by means that should probably be explicitly clarified * at some point. JG200106061204 */ char hname[NI_MAXHOST]; char ipname[NI_MAXHOST]; GetIPHost((struct sockaddr *)&dreq.dr_RSin, hname, sizeof(hname), ipname, sizeof(ipname)); bcopy(&dreq.dr_RSin, &dres.dr_Addr, sizeof(dres.dr_Addr)); /* Do forward DNS doublecheck */ if (hname[0] == 0) snprintf(dres.dr_Host, sizeof(dres.dr_Host), "%s", ipname); else if (TestForwardLookup(hname, ipname, (struct sockaddr *)&dreq.dr_RSin) < 0) dres.dr_DnsMismatch = 1; else snprintf(dres.dr_Host, sizeof(dres.dr_Host), "%s", hname); /* * call test */ if (DebugOpt) printf("call test, DnsTest %s (%s)\n", ipname, hname); if (hname[0]) DnsTest(&dreq, &dres, hname, NULL, ipname); else DnsTest(&dreq, &dres, NULL, NULL, ipname); } write(fd, &dres, sizeof(dres)); stprintf("dns idle"); } logit(LOG_NOTICE, "DNS process exiting n=%d/%d", n, sizeof(dreq)); } /* * Search a file of username:password pairs for a matching username/passord * * Returns: NULL failure * "100 Sucess" success * */ char * fileAuthenticate(char *user, char *pass, char *conf) { static char result[DEFNAMELEN + 16]; char *r = NULL; FILE *fp; char buffer[1024]; char *bptr; char *ptr; int negate = 0; if (*conf == '!') { negate = 1; conf++; } if (! ((fp = fopen(conf, "r")))) { logit(LOG_ERR, "unable to open auth file %s", conf); return(NULL); } while (!feof(fp)) { fgets(buffer, sizeof(buffer), fp); if ((ptr = strrchr(buffer, '\n'))) { *ptr = '\0'; } bptr = buffer; ptr = strsep(&bptr, ":"); if (ptr && ! strcmp(ptr, user)) { if (negate) return(NULL); ptr = strsep(&bptr, ":"); if (ptr && !strcmp(ptr, pass)) { ptr = strsep(&bptr, ":"); if (ptr) snprintf(result, sizeof(result), "110 %s", ptr); else strcpy(result, "100 Success"); r = result; } break; } } fclose(fp); if (r == NULL && negate) { strcpy(result, "100 Success"); r = result; } return(r); } #ifdef RADIUS_ENABLED /* * Send an authenticate request to a radius server * * Returns: NULL failure * "100 Sucess" success */ char * radiusAuthenticate(char *user, char *pass, char *conf) { static char result[DEFNAMELEN + 16]; char *r = NULL; struct rad_handle *h; int rval; if (! ((h = rad_open()))) { logit(LOG_ERR, "unable to rad_auth_open"); return(NULL); } if (rad_config(h, conf) < 0) { logit(LOG_ERR, "rad_config(%s) failed: %s", conf, rad_strerror(h)); rad_close(h); return(NULL); } if (rad_create_request(h, RAD_ACCESS_REQUEST) < 0) { logit(LOG_ERR, "rad_create_request failed: %s", rad_strerror(h)); rad_close(h); return(NULL); } if (rad_put_string(h, RAD_USER_NAME, user) < 0) { logit(LOG_ERR, "rad_put_string(RAD_USER_NAME) failed: %s", rad_strerror(h)); rad_close(h); return(NULL); } if (rad_put_string(h, RAD_USER_PASSWORD, pass) < 0) { logit(LOG_ERR, "rad_put_string(RAD_USER_PASSWORD) failed: %s", rad_strerror(h)); rad_close(h); return(NULL); } if (((rval = rad_send_request(h))) < 0) { logit(LOG_ERR, "rad_send_request failed: %s", rad_strerror(h)); rad_close(h); return(NULL); } rad_close(h); if (rval == RAD_ACCESS_ACCEPT) { strcpy(result, "100 Success"); r = result; } else r = NULL; return(r); } #endif #ifdef CDB_ENABLED /* * Search a CDB database for a matching username/passord * * Returns: NULL failure * "100 Sucess" success * */ char * cdbAuthenticate(char *user, char *pass, char *conf) { static char result[DEFNAMELEN + 16]; char *r = NULL; unsigned int pwlen = 0; int fd; int negate = 0; if (*conf == '!') negate = 1; fd = open(conf, O_RDONLY); if (fd < 0) { logit(LOG_ERR, "unable to open auth cdb %s", conf); return(NULL); } if (cdb_seek(fd, user, strlen(user), &pwlen) > 0) { if (negate) return(NULL); if (pwlen > 0) { char pw[64]; if (pwlen > sizeof(pw) - 1) pwlen = sizeof(pw) - 1; if (read(fd, pw, pwlen) == pwlen) { pw[pwlen] = 0; if (!strcmp(pw, pass)) { strcpy(result, "100 Success"); r = result; } } } } close(fd); if (r == NULL && negate) { strcpy(result, "100 Success"); r = result; } return(r); } #endif /* CDB_ENABLED */ #ifdef DB_ENABLED /* * Search a DB database for a matching username/passord * * Returns: NULL failure * "100 Sucess" success * */ char * dbAuthenticate(char *user, char *pass, char *conf) { static char result[DEFNAMELEN + 16]; char *r = NULL; DB *db = NULL; DBT key; DBT data; int negate = 0; int dbtype = DB_BTREE; if (*conf == '!') { negate = 1; conf++; } if (strncmp(conf, "hash_", 5) == 0) { dbtype = DB_HASH; conf += 5; } else if (strncmp(conf, "btree_", 6) == 0) { dbtype = DB_BTREE; conf += 6; } else if (strncmp(conf, "recno_", 6) == 0) { dbtype = DB_RECNO; conf += 6; } db = dbopen(conf, O_RDONLY, 0, dbtype, NULL); if (db == NULL) { logit(LOG_ERR, "unable to open auth db %s (%s)", conf, strerror(errno)); return(NULL); } key.data = user; key.size = strlen(user); if (db->get(db, &key, &data, 0) == 0) { char *p = data.data; int i = 0; if (negate) return(NULL); if (*pass) { if (strcmp(pass, p) != 0) return(NULL); while (i < data.size && *p) { p++; i++; } if (!*p && i < data.size) p++; i++; i = data.size - i; } else { i = data.size; } if (i > 0 && *p) { if (i > sizeof(result) - 5) i = sizeof(result) - 5; snprintf(result, i + 5, "110 %s", p); } else { strcpy(result, "100 Success"); } r = result; } else if (negate) { strcpy(result, "100 Success"); r = result; } db->close(db); return(r); } #endif /* DB_ENABLED */ #ifdef NETREMOTE_ENABLED /* * Send an authenticate request to a NetRemote server * * This is Yet Another Famous Joe Greco Simple Stupid Protocol * * My intended use was, due to a large number of reader machines that * maintained strong firewalls, to be able to centralize authentication * operations on a core set of servers so that maintenance would be * easier. * * Protocol is simple. Server starts by sending the time as a 12-digit * integer. Client responds with a packet length as a 12-digit integer, * and a DES-encrypted packet containing a random number, the server-sent * time, the encryption password, username being auth'd, and password * being auth'd. The server then returns 1-digit integer, 0 or 1, for * status. * * Returns: NULL failure * "100 Sucess" success */ /* really needs to be a multiple of 8 for DES encrypt */ #define NETREMOTE_DATASIZE 1432 int xread(fd, buf, siz) int fd; char *buf; int siz; { int rval; int chrs = 0; while (siz) { if ((rval = read(fd, buf, siz)) <= 0) { return(rval); } chrs += rval; siz -= rval; buf += rval; } return(chrs); } /* * This needs a rework. * * Since we do not record what authenticator gave us access, or * the parameters to it, this really stinks. * * Ideally the whole dns module should be retrofitted a bit to * allow future callbacks... */ void netRemoteAccounting(DnsReq *dreq) { char *conf = "Password@accounting.server:8998"; int fd = -1, port = 8998; char buffer[NETREMOTE_DATASIZE], output[NETREMOTE_DATASIZE], *ptr, *optr; char confpw[1024], confhn[1024], *colon; long theirtime; des_cblock key; des_key_schedule sched; struct sockaddr_in sin; struct hostent *hptr; snprintf(confpw, sizeof(confpw), "%s", conf); if ((ptr = strchr(confpw, '@'))) { *ptr = '\0'; snprintf(confhn, sizeof(confhn), "%s", ptr + 1); } else { snprintf(confpw, sizeof(confpw), "%s", "none"); snprintf(confhn, sizeof(confhn), "%s", conf); } if ((colon = strrchr(confhn, ':'))) { int bad = 0; *colon = '\0'; ptr = colon + 1; if (! *ptr) { bad++; } while (*ptr) { if (! isdigit(*ptr)) { bad++; } ptr++; } if (! bad) { port = atoi(colon + 1); } else { logit(LOG_ERR, "Invalid NetRemote port %s", colon + 1); } } /* attach to remote server(s) */ if (isdigit(*confhn)) { if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { logit(LOG_ERR, "NetRemote socket create: %m"); return; } bzero((void *)&sin, sizeof(&sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = INADDR_ANY; sin.sin_port = htons(0); if (bind(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) { close(fd); logit(LOG_ERR, "NetRemote socket bind: %m"); return; } bzero((void *)&sin, sizeof(&sin)); sin.sin_family = AF_INET; sin.sin_port = htons(port); sin.sin_addr.s_addr = inet_addr(confhn); if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) { close(fd); logit(LOG_ERR, "NetRemote socket connect: %s(%s:%d): %m", confhn, inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)); return; } } else { int i = 0, connected = 0; if (! (hptr = gethostbyname(confhn))) { close(fd); logit(LOG_ERR, "NetRemote gethostbyname: %s: %m", confhn); return; } while (! connected) { if (! hptr->h_addr_list[i]) { return; } if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { logit(LOG_ERR, "NetRemote socket create: %m"); return; } bzero((void *)&sin, sizeof(&sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = INADDR_ANY; sin.sin_port = htons(0); if (bind(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) { close(fd); logit(LOG_ERR, "NetRemote socket bind: %m"); return; } bzero((void *)&sin, sizeof(&sin)); sin.sin_family = AF_INET; sin.sin_port = htons(port); bcopy(hptr->h_addr_list[i], (char *)&sin.sin_addr.s_addr, sizeof(sin.sin_addr.s_addr)); if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) { if (errno != ETIMEDOUT && errno != ECONNREFUSED && errno != ENETUNREACH) { close(fd); logit(LOG_ERR, "NetRemote fatal socket connect: %s: %m", confhn); return; } close(fd); logit(LOG_ERR, "NetRemote socket connect: %s(%s:%d): %m", confhn, inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)); i++; } else { connected++; } } } /* Read the server's idea of time. 12 byte int plus \n */ if (xread(fd, buffer, 13) != 13) { close(fd); return; } theirtime = atol(buffer); des_string_to_key(confpw, &key); des_set_key(&key, sched); bzero(buffer, sizeof(buffer)); snprintf(buffer, sizeof(buffer), "%ld\n%ld\n%s\n%c\n%s\n%.0f\n%d\n%d\n%.0f\n%d\n%d\n%.0f\n%.0f\n%.0f\n%.0f\n%.0f\n%.0f\n%.0f\n%d\n%s\n", random(), theirtime, confpw, '2', dreq->dr_AuthUser, dreq->dr_ByteCount, dreq->dr_GrpCount, dreq->dr_ArtCount, dreq->dr_PostBytes, dreq->dr_PostCount, dreq->dr_PostFailCount, dreq->dr_ByteCountArticle, dreq->dr_ByteCountHead, dreq->dr_ByteCountBody, dreq->dr_ByteCountList, dreq->dr_ByteCountXover, dreq->dr_ByteCountXhdr, dreq->dr_ByteCountOther, (int)dreq->dr_SessionLength, NetAddrToSt(0, (struct sockaddr *)&dreq->dr_RSin, 1, 0, 1)); ptr = buffer; optr = output; while (ptr < buffer + sizeof(buffer)) { des_ecb_encrypt((des_cblock *)ptr,(des_cblock *)optr, sched, 1); bzero(ptr, 8); ptr += 8; optr += 8; } /* Send the encrypted request, prefixed by size of packet */ snprintf(buffer, sizeof(buffer), "%012d\n", sizeof(output)); write(fd, buffer, strlen(buffer)); write(fd, output, sizeof(output)); /* No response to read */ close(fd); return; } char * netRemoteAuthenticate(char *user, char *pass, char *conf, char *localip) { static char result[DEFNAMELEN + 16]; char *r = NULL; int fd = -1, port = 8998; char buffer[NETREMOTE_DATASIZE], output[NETREMOTE_DATASIZE], *ptr, *optr; char confpw[1024], confhn[1024], *colon; long theirtime; des_cblock key; des_key_schedule sched; struct sockaddr_in sin; struct hostent *hptr; snprintf(confpw, sizeof(confpw), "%s", conf); if ((ptr = strchr(confpw, '@'))) { *ptr = '\0'; snprintf(confhn, sizeof(confhn), "%s", ptr + 1); } else { snprintf(confpw, sizeof(confpw), "%s", "none"); snprintf(confhn, sizeof(confhn), "%s", conf); } if ((colon = strrchr(confhn, ':'))) { int bad = 0; *colon = '\0'; ptr = colon + 1; if (! *ptr) { bad++; } while (*ptr) { if (! isdigit(*ptr)) { bad++; } ptr++; } if (! bad) { port = atoi(colon + 1); } else { logit(LOG_ERR, "Invalid NetRemote port %s", colon + 1); } } /* attach to remote server(s) */ if (isdigit(*confhn)) { if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { logit(LOG_ERR, "NetRemote socket create: %m"); return(NULL); } bzero((void *)&sin, sizeof(&sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = INADDR_ANY; sin.sin_port = htons(0); if (bind(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) { close(fd); logit(LOG_ERR, "NetRemote socket bind: %m"); return(NULL); } bzero((void *)&sin, sizeof(&sin)); sin.sin_family = AF_INET; sin.sin_port = htons(port); sin.sin_addr.s_addr = inet_addr(confhn); if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) { close(fd); logit(LOG_ERR, "NetRemote socket connect: %s(%s:%d): %m", confhn, inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)); return(NULL); } } else { int i = 0, connected = 0; if (! (hptr = gethostbyname(confhn))) { close(fd); logit(LOG_ERR, "NetRemote gethostbyname: %s: %m", confhn); return(NULL); } while (! connected) { if (! hptr->h_addr_list[i]) { return(NULL); } if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { logit(LOG_ERR, "NetRemote socket create: %m"); return(NULL); } bzero((void *)&sin, sizeof(&sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = INADDR_ANY; sin.sin_port = htons(0); if (bind(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) { close(fd); logit(LOG_ERR, "NetRemote socket bind: %m"); return(NULL); } bzero((void *)&sin, sizeof(&sin)); sin.sin_family = AF_INET; sin.sin_port = htons(port); bcopy(hptr->h_addr_list[i], (char *)&sin.sin_addr.s_addr, sizeof(sin.sin_addr.s_addr)); if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) { if (errno != ETIMEDOUT && errno != ECONNREFUSED && errno != ENETUNREACH) { close(fd); logit(LOG_ERR, "NetRemote fatal socket connect: %s: %m", confhn); return(NULL); } close(fd); logit(LOG_ERR, "NetRemote socket connect: %s(%s:%d): %m", confhn, inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)); i++; } else { connected++; } } } /* Read the server's idea of time. 12 byte int plus \n */ if (xread(fd, buffer, 13) != 13) { close(fd); return(NULL); } theirtime = atol(buffer); des_string_to_key(confpw, &key); des_set_key(&key, sched); bzero(buffer, sizeof(buffer)); snprintf(buffer, sizeof(buffer), "%ld\n%ld\n%s\n%c\n%s\n%s\n%s\n", random(), theirtime, confpw, '1', user, pass, localip); ptr = buffer; optr = output; while (ptr < buffer + sizeof(buffer)) { des_ecb_encrypt((des_cblock *)ptr,(des_cblock *)optr, sched, 1); bzero(ptr, 8); ptr += 8; optr += 8; } /* Send the encrypted request, prefixed by size of packet */ snprintf(buffer, sizeof(buffer), "%012d\n", sizeof(output)); write(fd, buffer, strlen(buffer)); write(fd, output, sizeof(output)); /* Read the server's response. 1 byte int plus \n */ if (read(fd, buffer, sizeof(buffer)) < 2) { close(fd); return(NULL); } close(fd); if (*buffer == '1') { snprintf(result, sizeof(result), "%s", buffer); if ((r = strrchr(result, '\n'))) { *r = '\0'; } r = result; } else r = NULL; return(r); } #endif #ifdef LDAP_ENABLED #ifdef NEW_LDAP /* * Send an authenticate request to an LDAP server * * Returns: NULL failure * "100 Sucess" success * * Configuration is done via an LDAP URL of the form: * * ldap://hostname[:port]/dn?userPassword?scope?filter [username:passwd] * * where: * userPassword is the attribute that contains the clear text password, * usually called "userPassword". * * scope is probably normally "sub" or "base". * * filter consists of the username and password attributes and any * other site specific search options required to narrow a search * to a single user. The following values can be used and will * be replaced by the corresponding value supplied from Diablo. * * $USER$ username * $PASS$ password * $REALM$ authentication domain, if realms are used * * username:passwd is the username and password with which to * authenticate to the LDAP server. If they are not specified, * anonymous authentication is done. * * Example: * * ldap://host.example.com/dc=$REALM$,dn=example.com?userPassword?sub?(userName=$USER$) * */ char * LDAPAuthenticate(char *user, char *pass, char *realm, char *conf) { static LDAP *ld = NULL; char *result = NULL; char url[1024]; LDAPURLDesc *ludp; char *confst = NULL; char *r; char *p; LDAPMessage *res; LDAPMessage *m; int msgid; int rcode; char *ldapuser = NULL; char *ldappass = NULL; /* * Parse the configuration options to extract the URL and the * LDAP auth options */ r = strdup(conf); confst = strsep(&r, " \t"); if (confst != NULL) { p = r; while ((p = strsep(&r, " \t")) != NULL) { ldapuser = p; p = strchr(p, ':'); if (p != NULL) { *p++ = 0; ldappass = p; } } } else { confst = r; } if (ld != NULL && (confst == NULL || strcmp(confst, conf) != 0)) { ldap_unbind_s(ld); ld = NULL; } /* * Make a new connection to the LDAP server if one isn't already there */ if (ld == NULL) { if (ldap_is_ldap_url(confst) == 0) { logit(LOG_ERR, "Not an LDAP URL: %s\n", conf); free(confst); return(NULL); } if (ldap_url_parse(confst, &ludp) != 0) { logit(LOG_ERR,"Unable to parse LDAP URL: %s\n", confst); free(confst); return(NULL); } /* Open LDAP connection */ if ((ld = ldap_init(ludp->lud_host, ludp->lud_port)) == NULL) { /* Couldn't contact server - fail authentication attempt */ logit(LOG_ERR,"Unable to connect to LDAP server: %s\n", confst); free(confst); ldap_free_urldesc(ludp); return(NULL); } ldap_free_urldesc(ludp); if ((msgid = ldap_bind_s(ld, ldapuser, ldappass, LDAP_AUTH_SIMPLE)) != LDAP_SUCCESS) { /* Bind failed - fail auth attempt */ logit(LOG_ERR,"LDAP bind failed: %s\n", confst); free(confst); ldap_unbind_s(ld); ld = NULL; return(NULL); } if (DebugOpt) printf("Connection to LDAP server established\n"); } /* * Setup the search parameters and substitute the user, pass and domain * fields into the search URL */ { char *src = confst; char *dst = url; while (*src) { if (user && strncmp(src, "$USER$", 6) == 0) { src += 6; strcpy(dst, user); dst += strlen(user); } else if (pass && strncmp(src, "$PASSWD$", 8) == 0) { src += 8; strcpy(dst, pass); dst += strlen(pass); } else if (realm && strncmp(src, "$REALM$", 7) == 0) { src += 7; strcpy(dst, realm); dst += strlen(realm); } else { *dst++ = *src++; } } *dst = 0; if (DebugOpt) printf("URL: %s\n", url); } if (ldap_url_parse(url, &ludp) != 0) { logit(LOG_ERR,"Unable to parse LDAP URL: %s\n", url); free(confst); return(NULL); } /* * Perform the search */ if ((rcode = ldap_search_s(ld, ludp->lud_dn, ludp->lud_scope, ludp->lud_filter, ludp->lud_attrs, 0, &res)) != LDAP_SUCCESS) { logit(LOG_ERR,"LDAP search for %s failed: %s\n", url, ldap_err2string(rcode)); free(confst); ldap_unbind_s(ld); ldap_free_urldesc(ludp); ld = NULL; return(NULL); } ldap_free_urldesc(ludp); /* * Parse the results. */ if (DebugOpt) printf("Results:\n"); for (m = ldap_first_entry(ld, res); m != NULL; m = ldap_next_entry(ld, m)) { BerElement *ber; char *attr; int i; for (attr = ldap_first_attribute(ld, m, &ber); attr != NULL; attr = ldap_next_attribute(ld, m, ber)) { char **vals; if (DebugOpt) printf("attr: %s\n", attr); if ((vals = ldap_get_values(ld, m, attr)) != NULL) { for (i = 0; vals[i] != NULL; ++i) { if (strcmp(pass,vals[i])==0) result="100 Success"; if (DebugOpt) printf(" val: %s\n", vals[i]); } ldap_value_free(vals); } } } ldap_msgfree(res); #ifdef LDAP_DO_UNBIND ldap_unbind_s(ld); ld = NULL; #endif free(confst); return(result); } #else /* * Send an authenticate request to an LDAP server * * Returns: NULL failure * "100 Sucess" success */ char * LDAPAuthenticate(char *user, char *pass, char *conf) { static char result[DEFNAMELEN + 16]; char *r; static LDAP *ld = NULL; static LDAPURLDesc *ludp; LDAPMessage *res; LDAPMessage *mptr; char *ldappassattr = "userpassword"; int msgid; int rcode; char *filter; #ifndef LDAP_COMPARE char **bv_val; #else char *dn; #endif if (ld == NULL) { if (ldap_is_ldap_url(conf) == 0) { logit(LOG_ERR, "No LDAP URL: %s\n", conf); ld = NULL; return(NULL); } if (ldap_url_parse(conf, &ludp) != 0) { logit(LOG_ERR, "Unable to parse LDAP URL: %s\n", conf); ldap_free_urldesc(ludp); ld = NULL; return(NULL); } /* Open LDAP connection */ if ((ld = ldap_init(ludp->lud_host, ludp->lud_port)) == NULL) { /* Couldn't contact server - fail authentication attempt */ logit(LOG_ERR, "Unable to connect to LDAP server: %s\n", conf); ldap_free_urldesc(ludp); ld = NULL; return(NULL); } if ((msgid = ldap_bind_s(ld, NULL, NULL, LDAP_AUTH_SIMPLE)) != LDAP_SUCCESS) { /* Bind failed - fail auth attempt */ logit(LOG_ERR, "LDAP bind failed: %s\n", conf); ldap_free_urldesc(ludp); ld = NULL; return(NULL); } if (DebugOpt) printf("Connection to LDAP server established\n"); } /* Build the filter string and attributes */ if ((filter = (char *)malloc(strlen(ludp->lud_filter) + strlen(user) + 1)) == NULL) { /* Malloc failed - fail auth attempt */ logit(LOG_ERR, "LDAP malloc failed: %s\n", conf); ldap_unbind_s(ld); ldap_free_urldesc(ludp); ld = NULL; return(NULL); } sprintf(filter, ludp->lud_filter, user); /* Perform the search */ if ((rcode = ldap_search_s(ld, ludp->lud_dn, ludp->lud_scope, filter, ludp->lud_attrs, 0, &res)) != LDAP_SUCCESS) { /* Search failed - fail auth attempt */ logit(LOG_INFO, "LDAP search failed (%s): %s\n", user, ldap_err2string(rcode)); free(filter); ldap_unbind_s(ld); ldap_free_urldesc(ludp); ld = NULL; return(NULL); } /* See what we got back - we only care about the first response */ if ((mptr = ldap_first_entry(ld, res)) == NULL) { /* Error - fail auth attempt */ logit(LOG_INFO, "LDAP auth failed: %s\n", user); free(filter); ldap_unbind_s(ld); ldap_free_urldesc(ludp); return(NULL); } r = NULL; #ifdef LDAP_COMPARE dn = ldap_get_dn(ld, mptr); if (ldap_compare_s(ld, dn, ldappassattr, pass) == LDAP_COMPARE_TRUE) { strcpy(result, "100 Success"); r = result; } else { logit(LOG_INFO, "LDAP auth failed: %s\n", user); r = NULL; } free(dn); #else /* Read the password and compare it */ bv_val = ldap_get_values(ld, mptr, ldappassattr); if (ldap_count_values(bv_val) == 0) { /* No password value returned - fail auth attempt */ logit(LOG_INFO, "LDAP auth failed: %s\n", user); r = NULL; ldap_value_free(bv_val); } if (strcmp(bv_val[0], pass) == 0) { strcpy(result, "100 Success"); r = result; } else { r = NULL; } #endif return(r); } #endif /* NEW_LDAP */ #endif /* LDAP_ENABLED */ #ifdef PERL_ENABLED EXTERN_C void xs_init (pTHXo); EXTERN_C void boot_DynaLoader (pTHXo_ CV* cv); EXTERN_C void xs_init(pTHXo) { char *file = __FILE__; dXSUB_SYS; /* DynaLoader is a special case */ newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file); } char *call_checkuser(char *auth_args[]) { static char buff[DEFNAMELEN + 16]; dSP; SV *sv; char *str; STRLEN len; char *result = NULL; ENTER; SAVETMPS; call_argv("checkuser", G_SCALAR, auth_args); SPAGAIN; sv = POPs; if (SvTRUE(sv) && (str = SvPV(sv, len)) && len < DEFNAMELEN + 16) result = strcpy(buff, str); FREETMPS; LEAVE; return result; } char *PerlAuthenticate(char *user, char *pass, char *conf) { char *embedding[] = { "", conf }; char *auth_args[] = { user, pass, NULL }; char *result; char *reslog; static PerlInterpreter *perl = NULL; int exitstatus = 0; if (perl == NULL) { if((perl = perl_alloc()) == NULL) { fprintf(stderr, "perl_alloc no memory\n"); exit(1); } PL_perl_destruct_level = 0; perl_construct(perl); exitstatus = perl_parse(perl, xs_init, 2, embedding, NULL); if (!exitstatus) { exitstatus = perl_run(perl); } if (exitstatus) { fprintf(stderr, "perl_parse or perl_run failed\n"); perl_destruct(perl); perl_free(perl); exit(exitstatus); } } reslog = result = call_checkuser(auth_args); if (reslog == NULL) reslog = "FAILED"; logit(LOG_INFO, "PERL auth request for %s: %s\n", user, reslog); return result; } #endif /* PERL_ENABLED */ #ifdef PAM_ENABLED static char *PAM_user; static char *PAM_password; static int PAM_error = 0; static int PAM_conv(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata) { int count; int replies = 0; struct pam_response *reply = NULL; for (count = 0; count < num_msg; count++) { switch (msg[count]->msg_style) { case PAM_PROMPT_ECHO_ON: reply = (struct pam_response *)realloc(reply, sizeof(struct pam_response)); reply[replies].resp_retcode = PAM_SUCCESS; reply[replies++].resp = strdup(PAM_user); break; case PAM_PROMPT_ECHO_OFF: reply = (struct pam_response *)realloc(reply, sizeof(struct pam_response)); reply[replies].resp_retcode = PAM_SUCCESS; reply[replies++].resp = strdup(PAM_password); break; case PAM_TEXT_INFO: break; case PAM_ERROR_MSG: default: PAM_error = 1; if (reply != NULL) { free(reply); reply = NULL; } return PAM_CONV_ERR; } } if (reply != NULL) *resp = reply; return PAM_SUCCESS; } static struct pam_conv conv = { PAM_conv, NULL }; char *PamAuthenticate(char *user, char *pass, char *conf) { static char result[DEFNAMELEN + 16]; pam_handle_t *pamh = NULL; int retval; char *r = NULL; PAM_user = user; PAM_password = pass; retval = pam_start(conf, PAM_user, &conv, &pamh); if (retval == PAM_SUCCESS) retval = pam_authenticate(pamh, 0); if (retval == PAM_SUCCESS) { strcpy(result, "100 Success"); r = result; } if (pam_end(pamh, retval) != PAM_SUCCESS) { pamh = NULL; logit(LOG_CRIT, "Unable to release PAM authentication\n"); } return(r); } #endif /* PAM_ENABLE */ /* * DnsTest() - test access file entry against host. * * fqdn reverse lookup of name, if known, or NULL * ary aliases, if known, or NULL * ipname name of host as dotted quad */ void DnsTest(DnsReq *dreq, DnsRes *dres, char *fqdn, char **ary, const char *ipname) { int AuthNeeded; int MatchedAuthNeeded = 0; int Authenticated = 0; int MatchedAuthenticated = 0; int MatchType; char *AuthReader = NULL; Vserver *vsp = NULL; AccessDef *alp; AccessDef *matchedalp = NULL; AccessDef accessdef; AccessDef matchedaccessdef; int acount; int DoneIdent = 0; int accessok; int accessfile; int firstmatch; FILE *af = NULL; char *realm = NULL; /* This got trashed, so reset it */ if (*dreq->dr_AuthUser) { dres->dr_ResultFlags = DR_REQUIRE_DNS; strcpy(dres->dr_AuthUser, dreq->dr_AuthUser); strcpy(dres->dr_AuthPass, dreq->dr_AuthPass); } /* XXX Doesn't work after INET6 addition!! */ for (vsp = accessmap.VServerList, acount = 0; acount < accessmap.VServerCount; acount++, vsp++) { #ifdef INET6 struct sockaddr_in6 *sa = (struct sockaddr_in6 *)&dreq->dr_LSin; struct sockaddr_in6 *vsa = (struct sockaddr_in6 *)&vsp->vs_Interface; if (memcmp(&sa->sin6_addr, &vsa->sin6_addr, sizeof(sa->sin6_addr)) == 0) { #else struct sockaddr_in *sa = (struct sockaddr_in *)&dreq->dr_LSin; struct sockaddr_in *vsa = (struct sockaddr_in *)&vsp->vs_Interface; if (sa->sin_addr.s_addr == vsa->sin_addr.s_addr) { #endif strcpy(dres->dr_VServer, vsp->vs_Name); dres->dr_VServerDef = vsp; break; } } accessok = 1; accessfile = 0; /* * Not sure if this is still needed as we only ever call DnsTest() * from DnsTask(), which hopefully sets this up correctly. */ if (!ipname) if (fqdn && IsIpAddr(fqdn)) ipname = fqdn; /* * For logging purposes, put something here */ snprintf(dres->dr_Host, sizeof(dres->dr_Host), "%s", ipname); /* * If we have specified a separate access file for a vserver, * then load it into memory for scanning. */ if (*dres->dr_VServer && *dres->dr_VServerDef->vs_AccessFile) { accessfile = 1; strcpy(accessdef.ad_Reader, "DEFAULT"); if (DebugOpt) printf("Using accessfile: %s\n", PatLibExpand(dres->dr_VServerDef->vs_AccessFile)); if ((af = fopen(PatLibExpand(dres->dr_VServerDef->vs_AccessFile), "r")) == NULL) { logit(LOG_CRIT, "Unable to open %s", PatLibExpand(dres->dr_VServerDef->vs_AccessFile)); accessok = 0; } } /* * Go through interations of the access list or read a vserver * access file and look for matches. Last match wins. * * We use the following logic for a match: * - if no match -> fail * - if last match with no auth required -> pass * - if last match with auth required (and no auth details) and no * previous match -> pass (requires auth to do things) * - if last match with auth required (and no auth details) and prev * match -> pass with prev match * - if last match with auth required (with matching auth details) -> pass * - if no auth required and no read,post,feed or status -> fail */ alp = accessmap.AccessList; matchedalp = NULL; acount = 0; firstmatch = 1; while (accessok) { stprintf("dns auth search %s", ipname); if (accessfile == 1) { if (readAccessLine(af, (char *)PatLibExpand(dres->dr_VServerDef->vs_AccessFile), &accessdef) != 1) break; alp = &accessdef; } else if (accessfile == 2) { if (acount++ > 1) break; } else { if (!firstmatch) alp++; firstmatch = 0; if (acount++ >= accessmap.AccessCount || alp == NULL) break; } /* * First we test the hostname or IP. */ MatchType = 0; if (IsIpAddr(alp->ad_Pattern)) { if (!ipname || !*ipname) continue; if (strchr(alp->ad_Pattern, '*') || strchr(alp->ad_Pattern, '?')) { /* Wildmatch */ if (WildCaseCmp(alp->ad_Pattern, ipname) != 0) continue; } else if (strchr(alp->ad_Pattern, '/')) { /* CIDR notation */ if (!CidrMatch(alp->ad_Pattern, ipname)) continue; } else { /* Default - exact match */ if (strcasecmp(ipname, alp->ad_Pattern) != 0) continue; } snprintf(dres->dr_Host, sizeof(dres->dr_Host), "%s", ipname); MatchType = 1; } else if (strncmp(alp->ad_Pattern, "db:", 3) == 0) { /* * If we have specified a DB for IP address lookup, then do * the lookup. */ #ifdef DB_ENABLED char *conf = alp->ad_Pattern + 3; char *res; if (DebugOpt) printf("Using accessdb: %s\n", conf); res = dbAuthenticate((char *)ipname, "", conf); if (DebugOpt) printf("accessdb result: %s\n", res ? res : "(NULL)"); if (res == NULL || strcmp(res, "110 0") == 0) continue; MatchType = 1; snprintf(dres->dr_Host, sizeof(dres->dr_Host), "%s", ipname); #else logit(LOG_ERR, "db: option in dreader.access not enabled - ignoring"); continue; #endif } else { if (!fqdn || !*fqdn) continue; if (strchr(alp->ad_Pattern, '*') || strchr(alp->ad_Pattern, '?')) { /* Wildmatch */ if (WildCaseCmp(alp->ad_Pattern, fqdn) != 0) continue; } else { /* Default - exact match */ if (strcasecmp(fqdn, alp->ad_Pattern) != 0) continue; } MatchType = 2; snprintf(dres->dr_Host, sizeof(dres->dr_Host), "%s", fqdn); } if (*alp->ad_IdentUser) { if (!DoneIdent && !*dres->dr_IdentUser) { /* * this isn't an option where the user can actually * enter something to pass the test; it is gained from * identd info. therefore it is an all-pass or all-fail * type thing. */ getAuthUser((struct sockaddr *)&dreq->dr_LSin, (struct sockaddr *)&dreq->dr_RSin, dres->dr_IdentUser, sizeof(dres->dr_IdentUser)); stprintf("dns auth ident %s", ipname); stprintf("dns auth search %s", ipname); DoneIdent = 1; } /* We don't need to go further if we fail the ident check */ if (strcmp(alp->ad_IdentUser, dres->dr_IdentUser) != 0) continue; } /* * Now me are matching an access line, check some of the * user details */ if (DebugOpt) printf("Matched access line: %s%s%s (%s)\n", *alp->ad_IdentUser ? alp->ad_IdentUser : "", *alp->ad_IdentUser ? "@" : "", alp->ad_Pattern, alp->ad_Reader); SetAuthDetails(dres, alp->ad_Reader); /* * Do we log with the hostname */ if (dres->dr_ReaderDef->rd_UseVerifiedDns && fqdn && *fqdn) snprintf(dres->dr_Host, sizeof(dres->dr_Host), "%s", fqdn); /* * We can optionally deny an entry that doesn't have a DNS entry */ if (dres->dr_ReaderDef->rd_DenyNoDns && (!fqdn || !*fqdn)) { logit(LOG_ERR, "Denying host with no DNS entry: %s", ipname); continue; } /* * If we mismatch Fwd/Rev and we matched against a domain * then reject the connection for security reasons */ if (dres->dr_DnsMismatch && (dres->dr_ReaderDef->rd_DenyMismatchedDns || (dres->dr_DnsMismatch && MatchType != 1))) { if (DebugOpt) printf("Not allowing DNS Fwd/Rev Mismatch for: %s matching %s%s%s\n", ipname, *alp->ad_IdentUser ? alp->ad_IdentUser : "", *alp->ad_IdentUser ? "@" : "", alp->ad_Pattern); continue; } /* * We can optionally use the FQDN for logging even when * matched with an IP */ if (dres->dr_ReaderDef->rd_UseVerifiedDns && !dres->dr_DnsMismatch && fqdn && *fqdn) snprintf(dres->dr_Host, sizeof(dres->dr_Host), "%s", fqdn); /* * Ok. Now at this point, we either don't have a match on this * line, in which case we've already skipped to the next line, * or we have a match... but we may still need to authenticate. */ Authenticated = 0; AuthNeeded = 0; if (*dres->dr_AuthDef->au_Radius || *dres->dr_AuthDef->au_LDAP || *dres->dr_AuthDef->au_Perl || *dres->dr_AuthDef->au_PAM || *dres->dr_AuthDef->au_NetRemote || *dres->dr_AuthDef->au_File || *dres->dr_AuthDef->au_Cdb || *dres->dr_AuthDef->au_Db || *dres->dr_AuthDef->au_External || *dres->dr_AuthDef->au_User) AuthNeeded = 1; if (dres->dr_AuthDef->au_Ident && !DoneIdent && !*dres->dr_IdentUser) { /* * this isn't an option where the user can actually * enter something to pass the test; it is gained from * identd info. therefore it is an all-pass or all-fail * type thing. */ getAuthUser((struct sockaddr *)&dreq->dr_LSin, (struct sockaddr *)&dreq->dr_RSin, dres->dr_IdentUser, sizeof(dres->dr_IdentUser)); stprintf("dns auth search %s", ipname); DoneIdent = 1; } /* * The user has used the AUTHINFO comamnd - check the details * against various authentication mechanisms. * * All methods specified in the auth block are used and any of * them can match */ if (AuthNeeded) { char user[128]; int authok; /* * Add a default realm, if one not already specified */ if (*dres->dr_AuthDef->au_AddRealm) { realm = strchr(dreq->dr_AuthUser, '@'); if (*dreq->dr_AuthUser && ! realm) { int offset; offset = strlen(dres->dr_AuthUser); if (offset < sizeof(dres->dr_AuthUser) - 4) { snprintf(dres->dr_AuthUser + offset, sizeof(dres->dr_AuthUser) - offset, "@%s", dres->dr_AuthDef->au_AddRealm); snprintf(dreq->dr_AuthUser, sizeof(dreq->dr_AuthUser), "%s", dres->dr_AuthUser); } } } strncpy(user, dreq->dr_AuthUser, sizeof(user) - 1 ); user[sizeof(user) - 1] = '\0'; authok = 1; /* * The realm is anything after the '@' in a username * Make sure this matches, otherwise the others won't * match. Note: this strips the realm */ if (*dres->dr_AuthDef->au_Realm) { authok = 0; realm = strchr(user, '@'); if (realm != NULL) { *realm++ = '\0'; if (strcmp(dres->dr_AuthDef->au_Realm,"*") == 0 || strcmp(dres->dr_AuthDef->au_Realm, realm) == 0) authok = 1; } } /* * If the user was set in auth and we have Ident, we just compare */ if (authok && DoneIdent && *dres->dr_IdentUser && *dres->dr_AuthDef->au_User && !strcmp(dres->dr_IdentUser, dres->dr_AuthDef->au_User)) { Authenticated = 2; if (DebugOpt) printf("Authenticated via ident+user\n"); } #ifdef REJECT_DB { DBT key; DBT data; DB *db = NULL; if((db = dbopen(REJECT_DB, O_RDONLY , 0, DB_BTREE, NULL)) != NULL) { key.data = user; key.size = strlen(user); if((db->get(db, &key, &data, 0) == 0)) { logit(LOG_NOTICE, "User %s found in reject db, denying access",user); if(DebugOpt) printf("User %s found in reject db, denying access\n",user); Authenticated = -1; authok = 0; } db->close(db); } } #endif /* REJECT_DB */ /* * Check for the user+pass in a file */ if (authok && *dres->dr_AuthDef->au_File && *user && *dreq->dr_AuthPass) { stprintf("dns auth file %s@%s", user, ipname); AuthReader = fileAuthenticate(user, dreq->dr_AuthPass, dres->dr_AuthDef->au_File); stprintf("dns auth search %s", ipname); if (AuthReader != NULL && *AuthReader == '1') { if (*dres->dr_AuthDef->au_File != '!') Authenticated = 1; if (DebugOpt) printf("Authenticated via file (%s)\n", AuthReader); } else if (*dres->dr_AuthDef->au_File == '!') { Authenticated = -1; authok = 0; if (DebugOpt) printf("Authentication via file REJECTED\n"); } else { Authenticated = -1; if (DebugOpt) printf("Authentication via file FAILED\n"); } } #ifdef RADIUS_ENABLED /* * Check user+pass with radius server */ if (authok && *dres->dr_AuthDef->au_Radius && *user && *dreq->dr_AuthPass) { stprintf("dns auth radius %s@%s", user, ipname); AuthReader = radiusAuthenticate(user, dreq->dr_AuthPass, dres->dr_AuthDef->au_Radius); stprintf("dns auth search %s", ipname); if (AuthReader != NULL && *AuthReader == '1') { Authenticated = 1; if (DebugOpt) printf("Authenticated via radius\n"); } else { Authenticated = -1; if (DebugOpt) printf("Authentication via radius FAILED\n"); } } #else if (authok && *dres->dr_AuthDef->au_Radius && *user && *dreq->dr_AuthPass) { Authenticated = -1; if (DebugOpt) printf("Authentication via radius FAILED\n"); logit(LOG_ERR, "Radius authentication requested, but not enabled"); } #endif #ifdef CDB_ENABLED /* * Check for the user+pass in a CDB */ if (authok && *dres->dr_AuthDef->au_Cdb && *user && *dreq->dr_AuthPass) { stprintf("dns auth cdb %s@%s", user, ipname); AuthReader = cdbAuthenticate(user, dreq->dr_AuthPass, dres->dr_AuthDef->au_Cdb); stprintf("dns auth search %s", ipname); if (AuthReader != NULL && *AuthReader == '1') { if (*dres->dr_AuthDef->au_Cdb != '!') Authenticated = 1; if (DebugOpt) printf("Authenticated via cdb\n"); } else if (*dres->dr_AuthDef->au_Cdb == '!') { authok = 0; Authenticated = -1; if (DebugOpt) printf("Authentication via cdb REJECTED\n"); } else { Authenticated = -1; if (DebugOpt) printf("Authentication via cdb FAILED\n"); } } #else if (authok && *dres->dr_AuthDef->au_Cdb && *user && *dreq->dr_AuthPass) { Authenticated = -1; if (DebugOpt) printf("Authentication via cdb FAILED\n"); logit(LOG_ERR, "CDB authentication requested, but not enabled"); } #endif /* CDB_ENABLED */ #ifdef DB_ENABLED /* * Check for the user+pass in a DB */ if (authok && *dres->dr_AuthDef->au_Db && *user && *dreq->dr_AuthPass) { stprintf("dns auth db %s@%s", user, ipname); AuthReader = dbAuthenticate(user, dreq->dr_AuthPass, dres->dr_AuthDef->au_Db); stprintf("dns auth search %s", ipname); if (AuthReader != NULL && *AuthReader == '1') { if (*dres->dr_AuthDef->au_Db != '!') Authenticated = 1; if (DebugOpt) printf("Authenticated via db\n"); } else if (*dres->dr_AuthDef->au_Db == '!') { authok = 0; Authenticated = -1; if (DebugOpt) printf("Authentication via db REJECTED\n"); } else { Authenticated = -1; if (DebugOpt) printf("Authentication via db FAILED\n"); } } #else if (authok && *dres->dr_AuthDef->au_Db && *user && *dreq->dr_AuthPass) { Authenticated = -1; if (DebugOpt) printf("Authentication via db FAILED\n"); logit(LOG_ERR, "DB authentication requested, but not enabled"); } #endif /* DB_ENABLED */ #ifdef NETREMOTE_ENABLED /* * Check user+pass with NetRemote server */ if (authok && *dres->dr_AuthDef->au_NetRemote && *user && *dreq->dr_AuthPass) { stprintf("dns auth netremote %s@%s", user, ipname); AuthReader = netRemoteAuthenticate(user, dreq->dr_AuthPass, dres->dr_AuthDef->au_NetRemote, NetAddrToSt(0, (struct sockaddr *)&dreq->dr_LSin, 1, 0, 1)); stprintf("dns auth search %s", ipname); if (AuthReader != NULL && *AuthReader == '1') { Authenticated = 1; if (DebugOpt) printf("Authenticated via NetRemote: %s\n", AuthReader); } else { Authenticated = -1; if (DebugOpt) printf("Authentication via NetRemote FAILED\n"); } } #else if (authok && *dres->dr_AuthDef->au_NetRemote && *user && *dreq->dr_AuthPass) { Authenticated = -1; if (DebugOpt) printf("Authentication via NetRemote FAILED\n"); logit(LOG_ERR, "NetRemote authentication requested, but not enabled"); } #endif #ifdef LDAP_ENABLED /* * Check user+pass with LDAP server */ if (authok && *dres->dr_AuthDef->au_LDAP && *user && *dreq->dr_AuthPass) { stprintf("dns auth ldap %s@%s", user, ipname); #ifdef NEW_LDAP AuthReader = LDAPAuthenticate(user, dreq->dr_AuthPass, realm, dres->dr_AuthDef->au_LDAP); #else AuthReader = LDAPAuthenticate(user, dreq->dr_AuthPass, dres->dr_AuthDef->au_LDAP); #endif stprintf("dns auth search %s", ipname); if (AuthReader != NULL && *AuthReader == '1') { Authenticated = 1; if (DebugOpt) printf("Authenticated via LDAP\n"); } else { Authenticated = -1; if (DebugOpt) printf("Authentication via LDAP FAILED\n"); } } #else if (authok && *dres->dr_AuthDef->au_LDAP && *user && *dreq->dr_AuthPass) { Authenticated = -1; if (DebugOpt) printf("Authentication via LDAP FAILED\n"); logit(LOG_ERR, "LDAP authentication requested, but not enabled"); } #endif #ifdef PERL_ENABLED if (authok && *dres->dr_AuthDef->au_Perl && *user && *dreq->dr_AuthPass) { stprintf("dns auth perl %s@%s", user, ipname); AuthReader = PerlAuthenticate(user, dreq->dr_AuthPass, dres->dr_AuthDef->au_Perl); stprintf("dns auth search %s", ipname); if (AuthReader != NULL && *AuthReader == '1') { Authenticated = 1; if (DebugOpt) printf("Authenticated via Perl\n"); } else { Authenticated = -1; if (DebugOpt) printf("Authentication via Perl FAILED\n"); } } #else if (authok && *dres->dr_AuthDef->au_Perl && *user && *dreq->dr_AuthPass) { Authenticated = -1; if (DebugOpt) printf("Authentication via Perl FAILED\n"); logit(LOG_ERR, "Perl authentication requested, but not enabled"); } #endif #ifdef PAM_ENABLED /* * Check user+pass with radius server */ if (authok && *dres->dr_AuthDef->au_PAM && *user && *dreq->dr_AuthPass) { stprintf("dns auth PAM %s@%s", user, ipname); AuthReader = PamAuthenticate(user, dreq->dr_AuthPass, dres->dr_AuthDef->au_PAM); stprintf("dns auth search %s", ipname); if (AuthReader != NULL && *AuthReader == '1') { Authenticated = 1; if (DebugOpt) printf("Authenticated via PAM\n"); } else { Authenticated = -1; if (DebugOpt) printf("Authentication via PAM FAILED\n"); } } #else if (authok && *dres->dr_AuthDef->au_PAM && *user && *dreq->dr_AuthPass) { Authenticated = -1; if (DebugOpt) printf("Authentication via PAM FAILED\n"); logit(LOG_ERR, "PAM authentication requested, but not enabled"); } #endif /* * Check a user+pass specified in the auth config */ if (authok && *dres->dr_AuthDef->au_User && *user && *dres->dr_AuthDef->au_Pass && *dreq->dr_AuthPass) { if (!strcmp(user, dres->dr_AuthDef->au_User) && !strcmp(dreq->dr_AuthPass, dres->dr_AuthDef->au_Pass)) { Authenticated = 1; if (DebugOpt) printf("Authenticated via user+pass\n"); } else { Authenticated = -1; if (DebugOpt) printf("Authentication via user+pass FAILED\n"); } } } if (!AuthNeeded || /* AUTHINFO and matched */ (Authenticated > 0 && *dreq->dr_AuthPass) || /* Ident + user only */ (Authenticated == 2) || /* AUTHINFO and not failed auth, but no other match */ (Authenticated == 0 && (matchedalp == NULL)) ) { if (accessfile == 1) { memcpy(&matchedaccessdef, &accessdef, sizeof(accessdef)); matchedalp = &matchedaccessdef; MatchedAuthenticated = Authenticated; MatchedAuthNeeded = AuthNeeded; } else { matchedalp = alp; MatchedAuthenticated = Authenticated; MatchedAuthNeeded = AuthNeeded; } } if (matchedalp && matchedalp->ad_MatchExit) break; } if (accessfile == 1) fclose(af); if (matchedalp == NULL) { if (DebugOpt) printf("No access match\n"); dres->dr_Code = 0; return; } if (!dres->dr_ReaderDef->rd_IgnoreAuthInfo && *dreq->dr_AuthPass && MatchedAuthenticated <= 0) { if (DebugOpt) printf("Authentication failed\n"); dres->dr_Code = 0; return; } if (AuthReader && strncmp(AuthReader, "110 ", 4) == 0) { AuthReader += 4; strncpy(dres->dr_ReaderName, AuthReader, sizeof(dres->dr_ReaderName) - 1); dres->dr_ReaderName[sizeof(dres->dr_ReaderName) - 1] = '\0'; } else { strncpy(dres->dr_ReaderName, matchedalp->ad_Reader, sizeof(dres->dr_ReaderName) - 1); dres->dr_ReaderName[sizeof(dres->dr_ReaderName) - 1] = '\0'; } SetAuthDetails(dres, dres->dr_ReaderName); /* * Now we have checked against all the access lines and matchedalp * points to the last match */ if (DebugOpt > 1) PrintAuthDetails(dres); /* * okay, if this was an authentication request, and we didn't auth, * then return a failure */ dres->dr_Flags &= ~DF_AUTHREQUIRED; if (MatchedAuthNeeded && !MatchedAuthenticated) { dres->dr_Flags |= DF_AUTHREQUIRED; } /* * If we authenticated with AUTHUSER, mark that we have done so as * we would like to log the correct info in log lines */ if (MatchedAuthenticated <= 0) { dres->dr_AuthUser[0] = 0; dres->dr_Flags &= ~DF_AUTH; } else { dres->dr_Flags |= DF_AUTH; } dres->dr_Code = 1; if ((dres->dr_Flags & (DF_FEED|DF_READ|DF_POST|DF_STATUS|DF_AUTHREQUIRED)) == 0) dres->dr_Code = 0; } /* * IDENT * * getAuthUser() - authenticate the remote username by connecting to port * 113 and requesting the user id of the remote port. This * is used by X-Trace: and some authentication. */ void getAuthUser(const struct sockaddr *plsin, const struct sockaddr *prsin, char *ubuf, int ulen) { #ifdef INET6 /* * XXX This needs to be updated to do INET6 ident requests */ #else int cfd; int lport; int rport; int n; char buf[256]; struct sockaddr_in lsin; struct sockaddr_in rsin; memcpy(&lsin, plsin, sizeof(lsin)); memcpy(&rsin, prsin, sizeof(rsin)); rport = ntohs(rsin.sin_port); lport = ntohs(lsin.sin_port); lsin.sin_port = 0; lsin.sin_family = AF_INET; if ((cfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { return; } if (bind(cfd, (struct sockaddr *)&lsin, sizeof(lsin)) < 0) { perror("bind"); close(cfd); return; } rsin.sin_port = htons(113); rsin.sin_family = AF_INET; /* * Do asynchronous connection with 10 second timeout. The timeout is * necessary to deal with broken clients or firewalls. */ fcntl(cfd, F_SETFL, O_NONBLOCK); errno = 0; if (connect(cfd, (struct sockaddr *)&rsin, sizeof(rsin)) < 0) { fd_set wfds; struct timeval tv = { 10, 0 }; if (errno != EINPROGRESS) { close(cfd); return; } FD_ZERO(&wfds); FD_SET(cfd, &wfds); if (select(cfd + 1, NULL, &wfds, NULL, &tv) == 0) { close(cfd); cfd = -1; } } /* * Send query, interpret response * * write() may fail if connect() failed to establish a connection. */ if (cfd >= 0) { fcntl(cfd, F_SETFL, 0); sprintf(buf, "%d, %d\r\n", rport, lport); if (DebugOpt) printf("IDENTD COMMAND %s\n", buf); if (write(cfd, buf, strlen(buf)) != strlen(buf)) { n = -1; } else { fcntl(cfd, F_SETFL, O_NONBLOCK); n = readtoeof(cfd, buf, sizeof(buf) - 1, 10); } } else { n = -1; } if (n > 0) { char *uid; buf[n] = 0; if (DebugOpt) printf("IDENTD RESPONSE %s\n", buf); if ((uid = strstr(buf, "USERID")) != NULL) { uid = strchr(uid + 1, ':'); if (uid) { uid = strchr(uid + 1, ':'); if (uid) { uid = strtok(uid + 1, "\r\n: \t"); if (uid && strlen(uid) < ulen) { strncpy(ubuf, uid, sizeof(ubuf) - 1); ubuf[sizeof(ubuf) - 1] = '\0'; SanitizeString(ubuf); } } } } } if (cfd >= 0) close(cfd); #endif } int readExactly(int fd, void *buf, int bytes) { int r = 0; while (bytes > 0) { int n = read(fd, buf, bytes); if (n <= 0) { if (n < 0 && r == 0) r = -1; break; } buf = (char *)buf + n; bytes -= n; r += n; } return(r); } int readtoeof(int fd, void *buf, int bytes, int secs) { fd_set rfds; int r = 0; FD_ZERO(&rfds); for (;;) { struct timeval tv = { 0, 0 }; int n; tv.tv_sec = secs; FD_SET(fd, &rfds); if (select(fd + 1, &rfds, NULL, NULL, &tv) == 0) break; errno = 0; n = read(fd, buf, bytes); if (n == 0) break; if (n < 0) { if (errno == EWOULDBLOCK || errno == EINTR || errno == EAGAIN ) { continue; } break; } r += n; buf = (char *)buf + n; bytes -= n; } return(r); } void sigSegVDNS(int sigNo) { if (DFd >= 0) close(DFd); nice(20); for (;;) ; } int readAccessLine(FILE *af, char *fname, AccessDef *adef) { static int needread = 1; static int linecount = 0; static char buf[8192] = ""; static char *opt; static char *val; char *p; while (needread) { if (fgets(buf, sizeof(buf), af) == NULL) return(0); linecount++; opt = buf; while (isspace((int)*opt)) opt++; if (*opt == '#' || *opt == '\n' || *opt == '\0') continue; p = opt + 6; *p = '\0'; if (strcmp(opt, "access") == 0) { opt += 7; while (isspace((int)*opt)) opt++; bzero(adef, sizeof(AccessDef)); break; } else { logit(LOG_ERR, "%s: Invalid command %s in line %d", fname, opt, linecount); return(0); } } /* * At this point we should be pointing to the wildmat pattern */ if (opt == NULL) { logit(LOG_ERR, "%s: Missing wildmat in line %d", fname, linecount); needread = 1; return(0); } if (needread) { val = strtok(opt, " \t"); val = strtok(NULL, " \t"); if (val == NULL) { logit(LOG_ERR, "%s: Invalid readerdef in line %d", fname, linecount); needread = 1; return(0); } while (isspace((int)*val)) val++; if (*val == '#' || *val == '\n' || *val == '\0') { logit(LOG_ERR, "%s: Invalid readerdef in line %d", fname, linecount); needread = 1; return(0); } p = strchr(val, '\n'); if (p) *p = '\0'; strncpy(adef->ad_Reader, val, sizeof(adef->ad_Reader) - 1); adef->ad_Reader[sizeof(adef->ad_Reader) - 1] = '\0'; } p = strchr(opt, ','); if (p != NULL) { *p++ = '\0'; needread = 1; } else { p = opt; } { /* * Check for identuser@ */ char *q; if (*opt && (q = strchr(opt, '@')) != NULL) { *q++ = '\0'; strncpy(adef->ad_IdentUser, opt, sizeof(adef->ad_IdentUser) - 1); adef->ad_IdentUser[sizeof(adef->ad_IdentUser) - 1] = '\0'; opt = q; } } if (*opt && strlen(opt) < sizeof(adef->ad_Pattern)) { strncpy(adef->ad_Pattern, opt, sizeof(adef->ad_Pattern) - 1); adef->ad_Pattern[sizeof(adef->ad_Pattern) - 1] = '\0'; opt = p; return(1); } logit(LOG_ERR, "%s: Bad length for access %s in line %d", fname, opt, linecount); needread = 1; return(0); } /* * Install a new copy of the access cache * This is done by creating the new cache files first, locking and then * renaming the files. */ void InstallAccessCache() { struct stat st; char buf[1024]; int linecount = 0; int tfp; FILE *fp; FILE *vsf; FILE *grf; FILE *auf; FILE *rdf; FILE *raf; char *opt; char *val; Vserver vserver; GroupDef groupdef; AuthDef authdef; ReaderDef readerdef; GroupList *groupptr = NULL; AccessDef accessdef; int copt = OPT_NONE; char vsnewbuf[PATH_MAX]; char grnewbuf[PATH_MAX]; char aunewbuf[PATH_MAX]; char rdnewbuf[PATH_MAX]; char ranewbuf[PATH_MAX]; if ((stat(PatLibExpand(DReaderAccessPat), &st) == 0) && (st.st_mtime <= Access_LastUpdate)) return; logit(LOG_INFO, "Installing access cache"); if ((fp = fopen(PatLibExpand(DReaderAccessPat), "r")) == NULL) { logit(LOG_CRIT, "Unable to open %s (%s)", PatLibExpand(DReaderAccessPat), strerror(errno)); return; } if (fstat(fileno(fp), &st) != 0) { fclose(fp); return; } Access_LastUpdate = st.st_mtime; snprintf(vsnewbuf, sizeof(vsnewbuf), "%s.new", PatDbExpand(DRVserverCachePat)); snprintf(grnewbuf, sizeof(grnewbuf), "%s.new", PatDbExpand(DRGroupCachePat)); snprintf(aunewbuf, sizeof(aunewbuf), "%s.new", PatDbExpand(DRAuthCachePat)); snprintf(rdnewbuf, sizeof(rdnewbuf), "%s.new", PatDbExpand(DRReaderCachePat)); snprintf(ranewbuf, sizeof(ranewbuf), "%s.new", PatDbExpand(DRAccessCachePat)); if ((vsf = fopen(vsnewbuf, "w+")) == NULL) { logit(LOG_CRIT, "Unable to create %s (%s)", vsnewbuf, strerror(errno)); fclose(fp); return; } if ((grf = fopen(grnewbuf, "w+")) == NULL) { logit(LOG_CRIT, "Unable to create %s (%s)", grnewbuf, strerror(errno)); fclose(fp); fclose(vsf); return; } if ((auf = fopen(aunewbuf , "w+")) == NULL) { logit(LOG_CRIT, "Unable to create %s (%s)", aunewbuf, strerror(errno)); fclose(fp); fclose(vsf); fclose(grf); return; } if ((rdf = fopen(rdnewbuf, "w+")) == NULL) { logit(LOG_CRIT, "Unable to create %s (%s)", rdnewbuf, strerror(errno)); fclose(fp); fclose(vsf); fclose(grf); fclose(auf); return; } if ((raf = fopen(ranewbuf, "w+")) == NULL) { logit(LOG_CRIT, "Unable to create %s (%s)", ranewbuf, strerror(errno)); fclose(fp); fclose(vsf); fclose(grf); fclose(auf); fclose(rdf); return; } /* The first entry is the default */ bzero(&vserver, sizeof(vserver)); strcpy(vserver.vs_Name, "DEFAULT"); if (DOpts.ReaderHostName != NULL) strncpy(vserver.vs_HostName, DOpts.ReaderHostName, sizeof(vserver.vs_HostName) - 1); if (DOpts.ReaderHostName != NULL) strncpy(vserver.vs_ClusterName, DOpts.ReaderHostName, sizeof(vserver.vs_ClusterName) - 1); if (DOpts.ReaderPathHost != NULL) strncpy(vserver.vs_PostPath, DOpts.ReaderPathHost, sizeof(vserver.vs_PostPath) - 1); if (DOpts.NewsAdmin != NULL) strncpy(vserver.vs_NewsAdm, DOpts.NewsAdmin, sizeof(vserver.vs_NewsAdm) - 1); fwrite(&vserver, sizeof(vserver), 1, vsf); fwrite("DEFAULT\0", 8, 1, grf); groupdef.gr_Count = 1; fwrite("1\0", 2, 1, grf); fwrite("*\0", 2, 1, grf); bzero(&authdef, sizeof(authdef)); strcpy(authdef.au_Name, "DEFAULT"); fwrite(&authdef, sizeof(authdef), 1, auf); bzero(&readerdef, sizeof(readerdef)); strcpy(readerdef.rd_Name, "DEFAULT"); strcpy(readerdef.rd_Auth, "DEFAULT"); strcpy(readerdef.rd_Groups, "DEFAULT"); strcpy(readerdef.rd_ListGroups, "DEFAULT"); strcpy(readerdef.rd_PostGroups, "DEFAULT"); strcpy(readerdef.rd_Vserver, "DEFAULT"); fwrite(&readerdef, sizeof(readerdef), 1, rdf); while (fgets(buf, sizeof(buf), fp) != NULL) { linecount++; opt = buf; while (isspace((int)*opt)) opt++; opt = strtok(opt, " \t\n"); if (opt == NULL || *opt == '#' || *opt == '\n' || *opt == '\0') continue; val = strtok(NULL, "\n"); if (val == NULL || *val == '#') val = ""; else while (isspace((int)*val)) val++; if (strcmp(opt, "end") == 0) { switch (copt) { case OPT_NONE: logit(LOG_ERR, "Found 'end' without define in line %d", linecount); break; case OPT_VSERVER: if (!*vserver.vs_ClusterName) strcpy(vserver.vs_ClusterName, vserver.vs_HostName); if (strcmp(vserver.vs_Name, "DEFAULT") == 0) { long fpos; fpos = ftell(vsf); fseek(vsf, 0L, SEEK_SET); fwrite(&vserver, sizeof(vserver), 1, vsf); fseek(vsf, fpos, SEEK_SET); } else { fwrite(&vserver, sizeof(vserver), 1, vsf); } bzero(&vserver, sizeof(vserver)); break; case OPT_GROUPS: fwrite(groupdef.gr_Name, strlen(groupdef.gr_Name) + 1, 1, grf); zfreeStr(&DnsMemPool, &groupdef.gr_Name); { char buf[10]; struct GroupList *gpp; struct GroupList *gp; sprintf(buf, "%d", groupdef.gr_Count); fwrite(&buf, strlen(buf) + 1, 1, grf); gp = groupdef.gr_Groups; while (gp != NULL) { fwrite(gp->group, strlen(gp->group) + 1, 1, grf); gpp = gp; gp = gp->next; zfreeStr(&DnsMemPool, &gpp->group); zfree(&DnsMemPool, gpp, sizeof(GroupList)); } } bzero(&groupdef, sizeof(groupdef)); break; case OPT_AUTH: if (strcmp(authdef.au_Name, "DEFAULT") == 0) { long fpos; fpos = ftell(auf); fseek(auf, 0L, SEEK_SET); fwrite(&authdef, sizeof(authdef), 1, auf); fseek(auf, fpos, SEEK_SET); } else { fwrite(&authdef, sizeof(authdef), 1, auf); } bzero(&authdef, sizeof(authdef)); break; case OPT_READERGRP: if (strcmp(readerdef.rd_Name, "DEFAULT") == 0) { long fpos; fpos = ftell(rdf); fseek(rdf, 0L, SEEK_SET); fwrite(&readerdef, sizeof(readerdef), 1, rdf); fseek(rdf, fpos, SEEK_SET); } else { fwrite(&readerdef, sizeof(readerdef), 1, rdf); } bzero(&readerdef, sizeof(readerdef)); break; } copt = OPT_NONE; continue; } if (!*val) { logit(LOG_ERR, "dreader.access: Missing value/label for %s in line %d", opt, linecount); Access_LastUpdate = 0; continue; } /* Handle the definition options */ switch (copt) { case OPT_NONE: break; case OPT_VSERVER: if (*val && strcmp(opt, "clustername") == 0) { strncpy(vserver.vs_ClusterName, val, sizeof(vserver.vs_ClusterName) - 1); continue; } if (*val && strcmp(opt, "hostname") == 0) { strncpy(vserver.vs_HostName, val, sizeof(vserver.vs_HostName) - 1); continue; } if (*val && strcmp(opt, "postpath") == 0) { strncpy(vserver.vs_PostPath, val, sizeof(vserver.vs_PostPath) - 1); if (strcmp(val, "0") == 0) vserver.vs_PostPath[0] = 0; continue; } if (*val && strcmp(opt, "newsadmin") == 0) { strncpy(vserver.vs_NewsAdm, val, sizeof(vserver.vs_NewsAdm) - 1); continue; } if (*val && ((strcmp(opt, "organisation") == 0) || (strcmp(opt, "organization") == 0))) { strncpy(vserver.vs_Org, val, sizeof(vserver.vs_Org) - 1); continue; } if (*val && strcmp(opt, "abuseto") == 0) { strncpy(vserver.vs_AbuseTo, val, sizeof(vserver.vs_AbuseTo) - 1); continue; } if (*val && strcmp(opt, "cryptpw") == 0) { strncpy(vserver.vs_CryptPw, val, sizeof(vserver.vs_CryptPw) - 1); continue; } if (*val && strcmp(opt, "accessfile") == 0) { strncpy(vserver.vs_AccessFile, val, sizeof(vserver.vs_AccessFile) - 1); continue; } if (*val && strcmp(opt, "welcome") == 0) { strncpy(vserver.vs_Welcome, val, sizeof(vserver.vs_Welcome) - 1); continue; } if (*val && strcmp(opt, "interface") == 0) { #ifdef INET6 int error; struct addrinfo *res; error = getaddrinfo(val, 0, NULL, &res); if (error != 0) logit(LOG_ERR, "getaddrinfo: %s: %s\n", val, gai_strerror(error)); else memcpy(&vserver.vs_Interface, &res->ai_addr, res->ai_addrlen); #else struct sockaddr_in *sin = (struct sockaddr_in *)&vserver.vs_Interface; bzero(&vserver.vs_Interface, sizeof(vserver.vs_Interface)); sin->sin_family = AF_INET; sin->sin_addr.s_addr = inet_addr(val); #endif continue; } if (*val && strcmp(opt, "noxrefhostupdate") == 0) { if (*val == 'y' || *val == 'Y' || *val == '1') vserver.vs_NoXrefHostUpdate = 1; else vserver.vs_NoXrefHostUpdate = 0; continue; } if (*val && strcmp(opt, "noreadpath") == 0) { if (*val == 'y' || *val == 'Y' || *val == '1') vserver.vs_NoReadPath = 1; else vserver.vs_NoReadPath = 0; continue; } if (*val && strcmp(opt, "postcomments") == 0) { strncpy(vserver.vs_Comments, val, sizeof(vserver.vs_Comments) - 1); continue; } if (*val && strcmp(opt, "posttrailer") == 0) { strncpy(vserver.vs_PostTrailer, val, sizeof(vserver.vs_PostTrailer) - 1); continue; } logit(LOG_ERR, "dreader.access: Invalid vserverdef option : %s in line %d\n", opt, linecount); continue; case OPT_GROUPS: if (*val && strcmp(opt, "group") == 0) { if (groupdef.gr_Groups == NULL) { groupptr = zalloc(&DnsMemPool, sizeof(GroupList)); groupptr->group = zallocStr(&DnsMemPool, val); groupptr->next = NULL; groupdef.gr_Groups = groupptr; groupdef.gr_Count++; } else { groupptr->next = zalloc(&DnsMemPool, sizeof(GroupList)); groupptr = groupptr->next; groupptr->group = zallocStr(&DnsMemPool, val); groupptr->next = NULL; groupdef.gr_Count++; } continue; } logit(LOG_ERR, "dreader.access: Invalid groupdef option : %s in line %d\n", opt, linecount); continue; case OPT_AUTH: if (*val && strcmp(opt, "file") == 0) { strncpy(authdef.au_File, val, sizeof(authdef.au_File) - 1); continue; } if (*val && strcmp(opt, "cdb") == 0) { strncpy(authdef.au_Cdb, val, sizeof(authdef.au_Cdb) - 1); continue; } if (*val && strcmp(opt, "db") == 0) { strncpy(authdef.au_Db, val, sizeof(authdef.au_Db) - 1); continue; } if (*val && strcmp(opt, "external") == 0) { strncpy(authdef.au_External, val, sizeof(authdef.au_External) - 1); continue; } if (*val && strcmp(opt, "radius") == 0) { strncpy(authdef.au_Radius, val, sizeof(authdef.au_Radius) - 1); continue; } if (*val && strcmp(opt, "netremote") == 0) { strncpy(authdef.au_NetRemote, val, sizeof(authdef.au_NetRemote) - 1); continue; } if (*val && strcmp(opt, "ldap") == 0) { strncpy(authdef.au_LDAP, val, sizeof(authdef.au_LDAP) - 1); continue; } if (*val && strcmp(opt, "perl") == 0) { strncpy(authdef.au_Perl, val, sizeof(authdef.au_Perl) - 1); continue; } if (*val && strcmp(opt, "pam") == 0) { strncpy(authdef.au_PAM, val, sizeof(authdef.au_PAM) - 1); continue; } if (*val && strcmp(opt, "user") == 0) { strncpy(authdef.au_User, val, sizeof(authdef.au_User) - 1); continue; } if (*val && strcmp(opt, "pass") == 0) { strncpy(authdef.au_Pass, val, sizeof(authdef.au_Pass) - 1); continue; } if (*val && strcmp(opt, "addrealm") == 0) { strncpy(authdef.au_AddRealm, val, sizeof(authdef.au_AddRealm) - 1); continue; } if (*val && strcmp(opt, "realm") == 0) { strncpy(authdef.au_Realm, val, sizeof(authdef.au_Realm) - 1); continue; } if (*val && strcmp(opt, "ident") == 0) { if (*val == 'y' || *val == 'Y' || *val == '1') authdef.au_Ident = 1; else authdef.au_Ident = 0; continue; } logit(LOG_ERR, "dreader.access: Invalid authdef option : %s in line %d\n", opt, linecount); continue; case OPT_READERGRP: if (*val && strcmp(opt, "auth") == 0) { strncpy(readerdef.rd_Auth, val, sizeof(readerdef.rd_Auth) - 1); continue; } if (*val && strcmp(opt, "groups") == 0) { strncpy(readerdef.rd_Groups, val, sizeof(readerdef.rd_Groups) - 1); if (strcmp(readerdef.rd_ListGroups, "DEFAULT") == 0) strncpy(readerdef.rd_ListGroups, val, sizeof(readerdef.rd_Groups) - 1); if (strcmp(readerdef.rd_PostGroups, "DEFAULT") == 0) strncpy(readerdef.rd_PostGroups, val, sizeof(readerdef.rd_Groups) - 1); continue; } if (*val && strcmp(opt, "listgroups") == 0) { strncpy(readerdef.rd_ListGroups, val, sizeof(readerdef.rd_Groups) - 1); continue; } if (*val && strcmp(opt, "postgroups") == 0) { strncpy(readerdef.rd_PostGroups, val, sizeof(readerdef.rd_Groups) - 1); continue; } if (*val && strcmp(opt, "vserver") == 0) { strncpy(readerdef.rd_Vserver, val, sizeof(readerdef.rd_Vserver) - 1); continue; } if (*val && strcmp(opt, "read") == 0) { if (*val == 'y' || *val == 'Y' || *val == '1') readerdef.rd_Read = 1; else readerdef.rd_Read = 0; continue; } if (*val && strcmp(opt, "post") == 0) { if (*val == 'y' || *val == 'Y' || *val == '1') readerdef.rd_Post = 1; else readerdef.rd_Post = 0; continue; } if (*val && strcmp(opt, "feed") == 0) { if (*val == 'y' || *val == 'Y' || *val == '1') readerdef.rd_Feed = 1; else readerdef.rd_Feed = 0; continue; } if (*val && strcmp(opt, "status") == 0) { if (*val == 'y' || *val == 'Y' || *val == '1') readerdef.rd_Status = 1; else readerdef.rd_Status = 0; continue; } if (*val && strcmp(opt, "quiet") == 0) { if (*val == 'y' || *val == 'Y' || *val == '1') readerdef.rd_Quiet = 1; else readerdef.rd_Quiet = 0; continue; } if (*val && strcmp(opt, "controlpost") == 0) { if (*val == 'y' || *val == 'Y' || *val == '1') readerdef.rd_ControlPost = 1; else readerdef.rd_ControlPost = 0; continue; } if (*val && strcmp(opt, "maxconn") == 0) { readerdef.rd_MaxConnTotal = atoi(val); continue; } if (*val && strcmp(opt, "maxconnperhost") == 0) { readerdef.rd_MaxConnPerHost = atoi(val); continue; } if (*val && strcmp(opt, "maxconnperuser") == 0) { readerdef.rd_MaxConnPerUser = atoi(val); continue; } if (*val && strcmp(opt, "maxconnpergroup") == 0) { readerdef.rd_MaxConnPerGroup = atoi(val); continue; } if (*val && strcmp(opt, "maxconnpervs") == 0) { readerdef.rd_MaxConnPerVs = atoi(val); continue; } if (*val && strcmp(opt, "ratelimit") == 0) { getRateLimitCmds(val, &readerdef); continue; } if (*val && strcmp(opt, "ratelimittax") == 0) { readerdef.rd_RateLimitTax = atoi(val); continue; } if (*val && strcmp(opt, "bytelimit") == 0) { readerdef.rd_ByteLimit = atoi(val); continue; } if (*val && strcmp(opt, "pathcomponents") == 0) { readerdef.rd_PathComponents = atoi(val); continue; } if (*val && strcmp(opt, "idletimeout") == 0) { readerdef.rd_IdleTimeout = atoi(val); continue; } if (*val && strcmp(opt, "sessiontimeout") == 0) { readerdef.rd_SessionTimeout = atoi(val); continue; } if (*val && strcmp(opt, "allowdnsmismatch") == 0) { /* Historical option - ignore it */ logit(LOG_NOTICE, "dreader.access: Ignoring historical option 'allowdnsmismatch' in line %d", linecount); continue; } if (*val && strcmp(opt, "useverifieddns") == 0) { if (*val == 'y' || *val == 'Y' || *val == '1') readerdef.rd_UseVerifiedDns = 1; else readerdef.rd_UseVerifiedDns = 0; continue; } if (*val && strcmp(opt, "denymismatcheddns") == 0) { if (*val == 'y' || *val == 'Y' || *val == '1') readerdef.rd_DenyMismatchedDns = 1; else readerdef.rd_DenyMismatchedDns = 0; continue; } if (*val && strcmp(opt, "denynodns") == 0) { if (*val == 'y' || *val == 'Y' || *val == '1') readerdef.rd_DenyNoDns = 1; else readerdef.rd_DenyNoDns = 0; continue; } if (*val && strcmp(opt, "allownewnews") == 0) { if (*val == 'y' || *val == 'Y' || *val == '1') readerdef.rd_AllowNewnews = 1; else readerdef.rd_AllowNewnews = 0; continue; } if (*val && strcmp(opt, "grouplog") == 0) { if (*val == 'y' || *val == 'Y' || *val == '1') readerdef.rd_GroupLog = 1; else readerdef.rd_GroupLog = 0; continue; } if (*val && strcmp(opt, "spoolheaders") == 0) { if (*val == 'y' || *val == 'Y' || *val == '1') readerdef.rd_SpoolHeaders = 1; else readerdef.rd_SpoolHeaders = 0; continue; } if (*val && strcmp(opt, "ignoreauthinfo") == 0) { if (*val == 'y' || *val == 'Y' || *val == '1') readerdef.rd_IgnoreAuthInfo = 1; else readerdef.rd_IgnoreAuthInfo = 0; continue; } if (*val && strcmp(opt, "checkpostgroups") == 0) { if (*val == 'y' || *val == 'Y' || *val == '1') readerdef.rd_CheckPostGroups = 1; else readerdef.rd_CheckPostGroups = 0; continue; } if (*val && strcmp(opt, "logcmd") == 0) { if (*val == 'y' || *val == 'Y' || *val == '1') readerdef.rd_LogCmd = 1; else readerdef.rd_LogCmd = 0; continue; } logit(LOG_ERR, "dreader.access: Invalid readerdef option : %s in line %d\n", opt, linecount); continue; } /* Start of a new definition */ if (strcmp(opt, "vserverdef") == 0) { copt = OPT_VSERVER; bzero(&vserver, sizeof(vserver)); strncpy(vserver.vs_Name, val, sizeof(vserver.vs_Name) - 1); continue; } if (strcmp(opt, "groupdef") == 0) { copt = OPT_GROUPS; bzero(&groupdef, sizeof(groupdef)); groupdef.gr_Name = zallocStr(&DnsMemPool, val); groupdef.gr_Count = 0; groupdef.gr_Groups = NULL; continue; } if (strcmp(opt, "authdef") == 0) { copt = OPT_AUTH; bzero(&authdef, sizeof(authdef)); strncpy(authdef.au_Name, val, sizeof(authdef.au_Name) - 1); continue; } if (strcmp(opt, "readerdef") == 0) { copt = OPT_READERGRP; bzero(&readerdef, sizeof(readerdef)); strncpy(readerdef.rd_Name, val, sizeof(readerdef.rd_Name) - 1); readerdef.rd_ControlPost = 1; readerdef.rd_GroupLog = 1; readerdef.rd_CheckPostGroups = 1; readerdef.rd_LogCmd = -1; strcpy(readerdef.rd_Auth, "DEFAULT"); strcpy(readerdef.rd_Groups, "DEFAULT"); strcpy(readerdef.rd_ListGroups, "DEFAULT"); strcpy(readerdef.rd_PostGroups, "DEFAULT"); strcpy(readerdef.rd_Vserver, "DEFAULT"); continue; } if (strcmp(opt, "access") == 0) { char *p; char *q; bzero(&accessdef, sizeof(accessdef)); copt = OPT_NONE; p = strtok(val, " \t"); p = strtok(NULL, " \t"); if (p == NULL) { logit(LOG_ERR, "dreader.access: Invalid readerdef for access %s in line %d", val, linecount); continue; } while (*p == ' ' || *p == '\t') p++; if (!*p || strlen(p) > sizeof(accessdef.ad_Reader)) { logit(LOG_ERR, "dreader.access: Invalid readerdef for access %s in line %d", val, linecount); continue; } if (*p == '|') { p++; accessdef.ad_MatchExit = 1; } strncpy(accessdef.ad_Reader, p, sizeof(accessdef.ad_Reader) - 1); p = strtok(val, ","); p = strtok(NULL, ","); for (q = val; q != NULL; q = p, p = strtok(NULL, ",")) { char *pp = q; if ((q = strchr(pp, '@')) != NULL) { *q++ = '\0'; if (!*pp || strlen(pp) > sizeof(accessdef.ad_Pattern)) { logit(LOG_ERR, "dreader.access: Bad length for ident user %s in line %d", q, linecount); continue; } strncpy(accessdef.ad_IdentUser, pp, sizeof(accessdef.ad_IdentUser) - 1); } else { q = pp; } if (!*q || strlen(q) > sizeof(accessdef.ad_Pattern)) { logit(LOG_ERR, "dreader.access: Bad length for access %s in line %d", q, linecount); continue; } strncpy(accessdef.ad_Pattern, q, sizeof(accessdef.ad_Pattern) - 1); fwrite(&accessdef, sizeof(accessdef), 1, raf); } continue; } logit(LOG_ERR, "dreader.access: Invalid access definition : %s in line %d\n", opt, linecount); Access_LastUpdate = 0; } fclose(fp); fclose(vsf); fclose(grf); fclose(auf); fclose(rdf); fclose(raf); if (Access_LastUpdate == 0) { logit(LOG_ERR, "Errors in dreader.access file - not updating"); return; } /* * We create a lock file that means no other processes should make * updates from the cache. The lock file time is also checked to * cater for possible race conditions. */ if ((tfp = open(PatDbExpand(DRAccessLockPat), O_RDWR|O_CREAT, 0644)) <= 0) { logit(LOG_CRIT, "Cannot create access lock %s", PatDbExpand(DRAccessLockPat)); Access_LastUpdate = 0; return; } if (xflock(tfp, XLOCK_SH) < 0) { if (DebugOpt) printf("Unable to obtain access lock (%s)\n", strerror(errno)); Access_LastUpdate = 0; return; } rename(vsnewbuf, PatDbExpand(DRVserverCachePat)); rename(grnewbuf, PatDbExpand(DRGroupCachePat)); rename(aunewbuf, PatDbExpand(DRAuthCachePat)); rename(rdnewbuf, PatDbExpand(DRReaderCachePat)); rename(ranewbuf, PatDbExpand(DRAccessCachePat)); write(tfp, &tfp, 1); xflock(tfp, XLOCK_UN); close(tfp); } /* * ReadAccessCache(): mmap the various access cache files into memory * and set the pointers in the accessmap structure. This will be * used to set the pointers for each thread. * * This has amazing performance benefits and saves memory because * we use the static mmap area for all threads */ int ReadAccessCache() { int vsf; int grf; int auf; int rdf; int raf; int tfp; struct stat st; int i; time_t lastmod; int fail; if (DebugOpt > 1) printf("Checking access cache\n"); if (stat(PatDbExpand(DRAccessLockPat), &st) != 0 || st.st_mtime <= Cache_LastUpdate) { if (DebugOpt) printf("No lock or not changed\n"); return(0); } lastmod = st.st_mtime; /* Obtain a lock so that we know it won't disappear from under us */ if ((tfp = open(PatDbExpand(DRAccessLockPat), O_RDONLY)) <= 0) { logit(LOG_ERR, "Cannot open access lock %s", PatDbExpand(DRAccessLockPat)); return(0); } if (hflock(tfp, 0, XLOCK_SH) < 0) { if (DebugOpt) printf("No lock or not changed\n"); return(0); } if (DebugOpt) printf("Loading access cache\n"); fail = 0; /* We must be able to load all the files at the same time */ if ((vsf = open(PatDbExpand(DRVserverCachePat), O_RDONLY)) <= 0) { logit(LOG_CRIT, "Unable to open %s", PatDbExpand(DRVserverCachePat)); fail = 1; } if ((grf = open(PatDbExpand(DRGroupCachePat), O_RDONLY)) <= 0) { logit(LOG_CRIT, "Unable to open %s", PatDbExpand(DRGroupCachePat)); close(vsf); fail = 1; } if ((auf = open(PatDbExpand(DRAuthCachePat), O_RDONLY)) <= 0) { logit(LOG_CRIT, "Unable to open %s", PatDbExpand(DRAuthCachePat)); close(vsf); close(grf); fail = 1; } if ((raf = open(PatDbExpand(DRAccessCachePat), O_RDONLY)) <= 0) { logit(LOG_CRIT, "Unable to open %s", PatDbExpand(DRAccessCachePat)); close(vsf); close(grf); close(auf); fail = 1; } if ((rdf = open(PatDbExpand(DRReaderCachePat), O_RDONLY)) <= 0) { logit(LOG_CRIT, "Unable to open %s", PatDbExpand(DRReaderCachePat)); close(vsf); close(grf); close(auf); close(raf); fail = 1; } /* Now that the files are open, we can clear the lock */ hflock(tfp, 0, XLOCK_UN); close(tfp); if (fail) { if (accessmap.AccessList == NULL) return(-2); return(-1); } /* * Preserve the old accessmap for later munmap * We do this in case there is a race condition that removes the * map too early. (????) */ memcpy(&oldaccessmap, &accessmap, sizeof(accessmap)); oldaccessmap.VServerList = accessmap.VServerList; oldaccessmap.GroupsList = accessmap.GroupsList; oldaccessmap.AuthList = accessmap.AuthList; oldaccessmap.ReaderList = accessmap.ReaderList; oldaccessmap.GroupMap = accessmap.GroupMap; oldaccessmap.AccessList = accessmap.AccessList; accessmap.VServerList = NULL; accessmap.VServerCount = 0; accessmap.GroupsList = NULL; accessmap.GroupCount = 0; accessmap.GroupMap = NULL; accessmap.AuthList = NULL; accessmap.AuthCount = 0; accessmap.ReaderList = NULL; accessmap.ReaderCount = 0; accessmap.AccessList = NULL; accessmap.AccessCount = 0; fstat(vsf, &st); accessmap.VServerList = xmap(NULL, st.st_size, PROT_READ, MAP_SHARED, vsf, 0); accessmap.VServerCount = st.st_size / sizeof(Vserver); close(vsf); fstat(grf, &st); if (st.st_size > 0) { char *mapptr; GroupDef *gp; GroupDef *pgp = NULL; GroupList *gl; GroupList *pgl = NULL; accessmap.GroupMap = xmap(NULL, st.st_size, PROT_READ, MAP_SHARED, grf, 0); mapptr = accessmap.GroupMap; while (*mapptr) { gp = zalloc(&DnsMemPool, sizeof(GroupDef)); gp->gr_Groups = NULL; gp->gr_Next = NULL; if (accessmap.GroupsList == NULL) accessmap.GroupsList = gp; if (pgp) pgp->gr_Next = gp; gp->gr_Name = mapptr; mapptr += strlen(gp->gr_Name) + 1; gp->gr_Count = atoi(mapptr); mapptr += strlen(mapptr) + 1; pgl = NULL; for (i=0; i < gp->gr_Count; i++) { gl = zalloc(&DnsMemPool, sizeof(GroupList)); if (gp->gr_Groups == NULL) gp->gr_Groups = gl; if (pgl) pgl->next = gl; gl->group = zallocStr(&DnsMemPool, mapptr); mapptr += strlen(gl->group) + 1; gl->next = NULL; pgl = gl; } pgp = gp; accessmap.GroupCount++; } } close(grf); fstat(auf, &st); accessmap.AuthList = xmap(NULL, st.st_size, PROT_READ, MAP_SHARED, auf, 0); accessmap.AuthCount = st.st_size / sizeof(AuthDef); close(auf); fstat(rdf, &st); accessmap.ReaderList = xmap(NULL, st.st_size, PROT_READ, MAP_SHARED, rdf, 0); accessmap.ReaderCount = st.st_size / sizeof(ReaderDef); close(rdf); fstat(raf, &st); accessmap.AccessList = xmap(NULL, st.st_size, PROT_READ, MAP_SHARED, raf, 0); accessmap.AccessCount = st.st_size / sizeof(AccessDef); close(raf); Cache_LastUpdate = lastmod; return(1); } /* * Remove the old mmap entries now that all the threads have been updated */ void ClearOldAccessMap(void) { if (DebugOpt) printf("Clearing old accessmap\n"); if (oldaccessmap.VServerList != NULL) xunmap(oldaccessmap.VServerList, oldaccessmap.VServerCount * sizeof(Vserver)); if (oldaccessmap.GroupMap != NULL) { xunmap(oldaccessmap.GroupMap, oldaccessmap.GroupMapSize); zfree(&DnsMemPool, oldaccessmap.GroupsList, sizeof(GroupDef)); } if (oldaccessmap.AuthList != NULL) xunmap(oldaccessmap.AuthList, oldaccessmap.AuthCount * sizeof(AuthDef)); if (oldaccessmap.ReaderList != NULL) xunmap(oldaccessmap.ReaderList, oldaccessmap.ReaderCount * sizeof(ReaderDef)); if (oldaccessmap.AccessList != NULL) xunmap(oldaccessmap.AccessList, oldaccessmap.AccessCount * sizeof(AccessDef)); bzero(&oldaccessmap, sizeof(oldaccessmap)); } /* * Update all the mmap'ed authentication pointers because something chanaged */ void SetAuthDetails(DnsRes *dres, char *which) { int i; ReaderDef *rdp; Vserver *vsp; GroupDef *gdp; AuthDef *adp; if (DebugOpt) printf("Setting Auth Details for %s\n", which); for (rdp = accessmap.ReaderList, i = 0; i < accessmap.ReaderCount; i++, rdp++) if (strcmp(which, rdp->rd_Name) == 0) break; /* The first reader access line is the default */ if (i >= accessmap.ReaderCount) rdp = accessmap.ReaderList; dres->dr_ReaderDef = rdp; for (vsp = accessmap.VServerList, i = 0; i < accessmap.VServerCount; i++, vsp++) /* * If we are on a virtual interface, only check for the specified * vserver. */ if (*dres->dr_VServer) { if (strcmp(dres->dr_VServer, vsp->vs_Name) == 0) break; } else if (strcmp(rdp->rd_Vserver, vsp->vs_Name) == 0) break; /* The first VServer is always the default one */ if (i >= accessmap.VServerCount) vsp = accessmap.VServerList; dres->dr_VServerDef = vsp; for (gdp = accessmap.GroupsList, i = 0; i < accessmap.GroupCount; i++, gdp = gdp->gr_Next) { if (strcmp(rdp->rd_Groups, gdp->gr_Name) == 0) break; } /* The first group list is always everything */ if (i >= accessmap.GroupCount) gdp = accessmap.GroupsList; dres->dr_GroupDef = gdp; for (gdp = accessmap.GroupsList, i = 0; i < accessmap.GroupCount; i++, gdp = gdp->gr_Next) { if (strcmp(rdp->rd_ListGroups, gdp->gr_Name) == 0) break; } /* The first group list is always everything */ if (i >= accessmap.GroupCount) gdp = accessmap.GroupsList; dres->dr_ListGroupDef = gdp; for (gdp = accessmap.GroupsList, i = 0; i < accessmap.GroupCount; i++, gdp = gdp->gr_Next) { if (strcmp(rdp->rd_PostGroups, gdp->gr_Name) == 0) break; } /* The first group list is always everything */ if (i >= accessmap.GroupCount) gdp = accessmap.GroupsList; dres->dr_PostGroupDef = gdp; for (adp = accessmap.AuthList, i = 0; i < accessmap.AuthCount; i++, adp++) if (strcmp(rdp->rd_Auth, adp->au_Name) == 0) break; /* The first auth list is no access */ if (i >= accessmap.AuthCount) adp = accessmap.AuthList; dres->dr_AuthDef = adp; if (dres->dr_ReaderDef->rd_Read) dres->dr_Flags |= DF_READ; else dres->dr_Flags &= ~DF_READ; if (dres->dr_ReaderDef->rd_Post) dres->dr_Flags |= DF_POST; else dres->dr_Flags &= ~DF_POST; if (dres->dr_ReaderDef->rd_Feed) dres->dr_Flags |= DF_FEED; else dres->dr_Flags &= ~DF_FEED; if (dres->dr_ReaderDef->rd_Status) dres->dr_Flags |= DF_STATUS; else dres->dr_Flags &= ~DF_STATUS; if (dres->dr_ReaderDef->rd_Quiet) dres->dr_Flags |= DF_QUIET; else dres->dr_Flags &= ~DF_QUIET; if (dres->dr_ReaderDef->rd_GroupLog) dres->dr_Flags |= DF_GROUPLOG; else dres->dr_Flags &= ~DF_GROUPLOG; if (dres->dr_ReaderDef->rd_ControlPost) dres->dr_Flags |= DF_CONTROLPOST; else dres->dr_Flags &= ~DF_CONTROLPOST; } /* * This gets called for each thread to update the pointers if the * mmapped info had been updated */ void UpdateAuthDetails(ForkDesc *desc) { Connection *conn = desc->d_Data; if (DebugOpt) printf("Updating auth details\n"); if (conn && !conn->co_Auth.dr_StaticAuth) SetAuthDetails(&conn->co_Auth, conn->co_Auth.dr_ReaderName); } void getRateLimitCmds(char *opt, ReaderDef *rd) { int i; int rl; char *p; rl = atoi(opt); while (*opt && !isspace((int)*opt)) opt++; while (*opt && isspace((int)*opt)) opt++; if (!*opt) for (i = 0; i < DRBC_XXXX; i++) rd->rd_RateLimit[i] = rl; else for (p = strtok(opt, " ,"); p != NULL; p = strtok(NULL, " ,")) { if (strcmp(p, "other") == 0) rd->rd_RateLimit[DRBC_NONE] = rl; else if (strcmp(p, "article") == 0) rd->rd_RateLimit[DRBC_ARTICLE] = rl; else if (strcmp(p, "head") == 0) rd->rd_RateLimit[DRBC_HEAD] = rl; else if (strcmp(p, "body") == 0) rd->rd_RateLimit[DRBC_BODY] = rl; else if (strcmp(p, "list") == 0) rd->rd_RateLimit[DRBC_LIST] = rl; else if (strcmp(p, "xover") == 0) rd->rd_RateLimit[DRBC_XOVER] = rl; else if (strcmp(p, "xhdr") == 0) rd->rd_RateLimit[DRBC_XHDR] = rl; } } /* * PrintAuthDetails(): Used for debugging - print all auth info for a thread */ void PrintAuthDetails(DnsRes *dres) { int i; printf("dr_ReaderName: %s\n", dres->dr_ReaderName); printf("dr_Flags: %x\n", dres->dr_Flags); printf("rd_Name: %s\n", dres->dr_ReaderDef->rd_Name); printf(" rd_Read: %d\n", dres->dr_ReaderDef->rd_Read); printf(" rd_Post: %d\n", dres->dr_ReaderDef->rd_Post); printf(" rd_Auth: %s\n", dres->dr_ReaderDef->rd_Auth); printf(" rd_Groups: %s\n", dres->dr_ReaderDef->rd_Groups); printf(" rd_ListGroups: %s\n", dres->dr_ReaderDef->rd_ListGroups); printf(" rd_PostGroups: %s\n", dres->dr_ReaderDef->rd_PostGroups); printf(" rd_Vserver: %s\n", dres->dr_ReaderDef->rd_Vserver); printf(" rd_MaxConnTotal: %d\n", dres->dr_ReaderDef->rd_MaxConnTotal); printf(" rd_MaxConnPerHost: %d\n", dres->dr_ReaderDef->rd_MaxConnPerHost); printf(" rd_MaxConnPerUser: %d\n", dres->dr_ReaderDef->rd_MaxConnPerUser); printf(" rd_MaxConnPerGroup: %d\n", dres->dr_ReaderDef->rd_MaxConnPerGroup); printf(" rd_MaxConnPerVs: %d\n", dres->dr_ReaderDef->rd_MaxConnPerVs); printf(" rd_RateLimitTax: %d\n", dres->dr_ReaderDef->rd_RateLimitTax); printf(" rd_RateLimit: "); for (i = 0; i < DRBC_XXXX; i++) printf("%d ", dres->dr_ReaderDef->rd_RateLimit[i]); printf("\n"); printf(" rd_ByteLimit: %d\n", dres->dr_ReaderDef->rd_ByteLimit); printf(" rd_IdleTimeout: %d\n", dres->dr_ReaderDef->rd_IdleTimeout); printf(" rd_SessionTimeout: %d\n", dres->dr_ReaderDef->rd_SessionTimeout); printf(" rd_GroupLog: %d\n", dres->dr_ReaderDef->rd_GroupLog); printf(" rd_UseVerifiedDns: %d\n", dres->dr_ReaderDef->rd_UseVerifiedDns); printf(" rd_DenyMismatchedDns: %d\n", dres->dr_ReaderDef->rd_DenyMismatchedDns); printf(" rd_DenyNoDns: %d\n", dres->dr_ReaderDef->rd_DenyNoDns); printf(" rd_CheckPostGroups: %d\n", dres->dr_ReaderDef->rd_CheckPostGroups); printf(" rd_LogCmd: %d\n", dres->dr_ReaderDef->rd_LogCmd); printf("vs_Name: %s\n", dres->dr_VServerDef->vs_Name); printf(" vs_HostName: %s\n", dres->dr_VServerDef->vs_HostName); printf(" vs_ClusterName: %s\n", dres->dr_VServerDef->vs_ClusterName); printf(" vs_PostPath: %s\n", dres->dr_VServerDef->vs_PostPath); printf(" vs_NoXrefHostUpdate: %d\n", dres->dr_VServerDef->vs_NoXrefHostUpdate); printf(" vs_NoReadPath: %d\n", dres->dr_VServerDef->vs_NoReadPath); printf(" vs_NewsAdm: %s\n", dres->dr_VServerDef->vs_NewsAdm); printf(" vs_Org: %s\n", dres->dr_VServerDef->vs_Org); printf(" vs_AbuseTo: %s\n", dres->dr_VServerDef->vs_AbuseTo); printf(" vs_CryptPw: %s\n", dres->dr_VServerDef->vs_CryptPw); printf(" vs_Interface: %s\n", "XXX"); /* dres->dr_VServerDef->vs_Interface); */ printf(" vs_AccessFile: %s\n", dres->dr_VServerDef->vs_AccessFile); printf("au_Name: %s\n", dres->dr_AuthDef->au_Name); printf(" au_File: %s\n", dres->dr_AuthDef->au_File); printf(" au_Cdb: %s\n", dres->dr_AuthDef->au_Cdb); printf(" au_Db: %s\n", dres->dr_AuthDef->au_Db); printf(" au_External: %s\n", dres->dr_AuthDef->au_External); printf(" au_Radius: %s\n", dres->dr_AuthDef->au_Radius); printf(" au_NetRemote: %s\n", dres->dr_AuthDef->au_NetRemote); printf(" au_LDAP: %s\n", dres->dr_AuthDef->au_LDAP); printf(" au_Perl: %s\n", dres->dr_AuthDef->au_Perl); printf(" au_PAM: %s\n", dres->dr_AuthDef->au_PAM); printf(" au_User: %s\n", dres->dr_AuthDef->au_User); printf(" au_Pass: %s\n", dres->dr_AuthDef->au_Pass); printf(" au_AddRealm: %s\n", dres->dr_AuthDef->au_AddRealm); printf(" au_Realm: %s\n", dres->dr_AuthDef->au_Realm); printf(" au_Ident: %d\n", dres->dr_AuthDef->au_Ident); printf("gr_Name: %s (%d)\n", dres->dr_GroupDef->gr_Name, dres->dr_GroupDef->gr_Count); { GroupList *gp; int i; for (gp = dres->dr_GroupDef->gr_Groups, i = 0; i < dres->dr_GroupDef->gr_Count; i++, gp = gp->next) printf(" group: %s\n", gp->group); } }