mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
Make the daemon init it's own tickets.
Make it blacklist clients until the previous operation is not over. General bugfixing.
This commit is contained in:
@@ -14,72 +14,317 @@
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <netinet/in.h>
|
||||
#include <time.h>
|
||||
#include <krb5.h>
|
||||
#include <ldap.h>
|
||||
#include <sasl/sasl.h>
|
||||
|
||||
#define TMP_TEMPLATE "/tmp/kpasswd.XXXXXX"
|
||||
#define KPASSWD_PORT 464
|
||||
#define KPASSWD_TCP 1
|
||||
#define KPASSWD_UDP 2
|
||||
|
||||
struct blacklist {
|
||||
struct blacklist *next;
|
||||
char *address;
|
||||
pid_t pid;
|
||||
};
|
||||
|
||||
static struct blacklist *global_blacklist = NULL;
|
||||
|
||||
int check_blacklist(char *address)
|
||||
{
|
||||
struct blacklist *bl;
|
||||
|
||||
if (!global_blacklist) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (bl = global_blacklist; bl; bl = bl->next) {
|
||||
if (strcmp(address, bl->address) == 0) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int add_blacklist(pid_t pid, char *address)
|
||||
{
|
||||
struct blacklist *bl, *gbl;
|
||||
|
||||
bl = malloc(sizeof(struct blacklist));
|
||||
if (!bl) return -1;
|
||||
|
||||
bl->next = NULL;
|
||||
bl->pid = pid;
|
||||
bl->address = strdup(address);
|
||||
if (!bl->address) {
|
||||
free(bl);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!global_blacklist) {
|
||||
global_blacklist = bl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
gbl = global_blacklist;
|
||||
while (gbl->next) {
|
||||
gbl = gbl->next;
|
||||
}
|
||||
gbl->next = bl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int remove_blacklist(pid_t pid)
|
||||
{
|
||||
struct blacklist *bl, *pbl;
|
||||
|
||||
if (!global_blacklist) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
pbl = NULL;
|
||||
bl = global_blacklist;
|
||||
while (bl) {
|
||||
if (pid == bl->pid) {
|
||||
if (pbl == NULL) {
|
||||
global_blacklist = bl->next;
|
||||
} else {
|
||||
pbl->next = bl->next;
|
||||
}
|
||||
free(bl->address);
|
||||
free(bl);
|
||||
return 0;
|
||||
}
|
||||
pbl = bl;
|
||||
bl = bl->next;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int debug = 1;
|
||||
char *srv_pri_name = "kadmin/changepw";
|
||||
char *keytab_name = "FILE:/var/kerberos/krb5kdc/kpasswd.keytab";
|
||||
char *realm_name = "BLUEBOX.REDHAT.COM";
|
||||
char *ldap_uri = "ldap://rc1.bluebox.redhat.com:389";
|
||||
|
||||
static int get_krb5_ticket(char *tmpfile)
|
||||
{
|
||||
char *ccname;
|
||||
char *realm_name = NULL;
|
||||
krb5_context context = NULL;
|
||||
krb5_keytab keytab = NULL;
|
||||
krb5_ccache ccache = NULL;
|
||||
krb5_principal kprincpw;
|
||||
krb5_creds my_creds;
|
||||
krb5_get_init_creds_opt options;
|
||||
int krberr, ret;
|
||||
|
||||
krberr = krb5_init_context(&context);
|
||||
if (krberr) {
|
||||
fprintf(stderr, "Failed to init kerberos context\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
krberr = krb5_get_default_realm(context, &realm_name);
|
||||
if (krberr) {
|
||||
fprintf(stderr, "Failed to get default realm name: %s\n",
|
||||
krb5_get_error_message(context, krberr));
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
krberr = krb5_build_principal(context, &kprincpw,
|
||||
strlen(realm_name), realm_name,
|
||||
"kadmin", "changepw", NULL);
|
||||
if (krberr) {
|
||||
fprintf(stderr, "Unable to build principal: %s\n",
|
||||
krb5_get_error_message(context, krberr));
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
krberr = krb5_kt_resolve(context, keytab_name, &keytab);
|
||||
if (krberr) {
|
||||
fprintf(stderr, "Failed to read keytab file: %s\n",
|
||||
krb5_get_error_message(context, krberr));
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = asprintf(&ccname, "FILE:%s", tmpfile);
|
||||
if (ret == -1) {
|
||||
fprintf(stderr, "Out of memory!\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = setenv("KRB5CCNAME", ccname, 1);
|
||||
if (ret == -1) {
|
||||
fprintf(stderr, "Unable to set env. variable KRB5CCNAME!\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
krberr = krb5_cc_resolve(context, ccname, &ccache);
|
||||
if (krberr) {
|
||||
fprintf(stderr, "Failed to set cache name: %s\n",
|
||||
krb5_get_error_message(context, krberr));
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
memset(&my_creds, 0, sizeof(my_creds));
|
||||
memset(&options, 0, sizeof(options));
|
||||
|
||||
krb5_get_init_creds_opt_set_address_list(&options, NULL);
|
||||
krb5_get_init_creds_opt_set_forwardable(&options, 0);
|
||||
krb5_get_init_creds_opt_set_proxiable(&options, 0);
|
||||
/* set a very short lifetime, we don't keep the ticket around */
|
||||
krb5_get_init_creds_opt_set_tkt_life(&options, 300);
|
||||
|
||||
krberr = krb5_get_init_creds_keytab(context, &my_creds, kprincpw,
|
||||
keytab, 0, NULL,
|
||||
&options);
|
||||
|
||||
if (krberr) {
|
||||
fprintf(stderr, "Failed to init credentials: %s\n",
|
||||
krb5_get_error_message(context, krberr));
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
krb5_cc_initialize(context, ccache, kprincpw);
|
||||
if (krberr) {
|
||||
fprintf(stderr, "Failed to init ccache: %s\n",
|
||||
krb5_get_error_message(context, krberr));
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
krberr = krb5_cc_store_cred(context, ccache, &my_creds);
|
||||
if (krberr) {
|
||||
fprintf(stderr, "Failed to store creds: %s\n",
|
||||
krb5_get_error_message(context, krberr));
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
done:
|
||||
/* TODO: mem cleanup */
|
||||
if (keytab) krb5_kt_close(context, keytab);
|
||||
if (context) krb5_free_context(context);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ldap_sasl_interact(LDAP *ld, unsigned flags, void *priv_data, void *sit)
|
||||
{
|
||||
sasl_interact_t **in = sit;
|
||||
int i, ret = LDAP_OTHER;
|
||||
sasl_interact_t *in = NULL;
|
||||
int ret = LDAP_OTHER;
|
||||
char *realm_name = (char *)priv_data;
|
||||
|
||||
if (!ld) return LDAP_PARAM_ERROR;
|
||||
|
||||
for (i = 0; in[i] && in[i]->id != SASL_CB_LIST_END; i++) {
|
||||
switch(in[i]->id) {
|
||||
for (in = sit; in && in->id != SASL_CB_LIST_END; in++) {
|
||||
switch(in->id) {
|
||||
case SASL_CB_USER:
|
||||
in[i]->result = srv_pri_name;
|
||||
in[i]->len = strlen(srv_pri_name);
|
||||
in->result = srv_pri_name;
|
||||
in->len = strlen(srv_pri_name);
|
||||
ret = LDAP_SUCCESS;
|
||||
break;
|
||||
case SASL_CB_GETREALM:
|
||||
in[i]->result = realm_name;
|
||||
in[i]->len = strlen(realm_name);
|
||||
in->result = realm_name;
|
||||
in->len = strlen(realm_name);
|
||||
ret = LDAP_SUCCESS;
|
||||
break;
|
||||
default:
|
||||
if (debug > 0) {
|
||||
fprintf(stderr,
|
||||
"Unhandled SASL int. option %d\n",
|
||||
in[i]->id);
|
||||
in->id);
|
||||
}
|
||||
in[i]->result = NULL;
|
||||
in[i]->len = 0;
|
||||
in->result = NULL;
|
||||
in->len = 0;
|
||||
ret = LDAP_OTHER;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ldap_pwd_change(char *client_name, krb5_data pwd)
|
||||
int ldap_pwd_change(char *client_name, char *realm_name, krb5_data pwd)
|
||||
{
|
||||
char *tmpfile = NULL;
|
||||
int id, version;
|
||||
LDAP *ld = NULL;
|
||||
BerElement *ctrl = NULL;
|
||||
struct berval control;
|
||||
struct berval newpw;
|
||||
char hostname[1024];
|
||||
char *ldap_uri = NULL;
|
||||
struct berval **ncvals;
|
||||
char *ldap_base = NULL;
|
||||
char *filter;
|
||||
char *attrs[] = {"krbprincipalname", NULL};
|
||||
char *root_attrs[] = {"namingContexts", NULL};
|
||||
char *userdn = NULL;
|
||||
char *retoid = NULL;
|
||||
struct berval *retdata = NULL;
|
||||
struct timeval tv;
|
||||
LDAPMessage *entry, *res = NULL;
|
||||
int ret;
|
||||
|
||||
tmpfile = strdup(TMP_TEMPLATE);
|
||||
if (!tmpfile) {
|
||||
fprintf(stderr, "Out of memory!\n");
|
||||
ret = KRB5_KPASSWD_HARDERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = mkstemp(tmpfile);
|
||||
if (ret == -1) {
|
||||
fprintf(stderr,
|
||||
"Failed to create tmp file with errno: %d\n", errno);
|
||||
ret = KRB5_KPASSWD_HARDERROR;
|
||||
goto done;
|
||||
}
|
||||
/* close mimmediately, we don't need to keep the file open,
|
||||
* just that it exist and has a unique name */
|
||||
close(ret);
|
||||
|
||||
/* In the long term we may want to do this in the main daemon
|
||||
* and just renew when needed.
|
||||
* Right now do it at every password change for robustness */
|
||||
ret = get_krb5_ticket(tmpfile);
|
||||
if (ret) {
|
||||
fprintf(stderr, "Unable to kinit!\n");
|
||||
ret = KRB5_KPASSWD_HARDERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
newpw.bv_len = pwd.length;
|
||||
newpw.bv_val = pwd.data;
|
||||
|
||||
/* retrieve server name and build uri */
|
||||
ret = gethostname(hostname, 1023);
|
||||
if (ret == -1) {
|
||||
fprintf(stderr, "Unable to get the hostname!\n");
|
||||
ret = KRB5_KPASSWD_HARDERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = asprintf(&ldap_uri, "ldap://%s:389", hostname);
|
||||
if (ret == -1) {
|
||||
fprintf(stderr, "Out of memory!\n");
|
||||
ret = KRB5_KPASSWD_HARDERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* connect to ldap server */
|
||||
/* TODO: support referrals ? */
|
||||
ret = ldap_initialize(&ld, ldap_uri);
|
||||
if(ret != LDAP_SUCCESS) {
|
||||
fprintf(stderr, "Unable to connect to ldap server");
|
||||
ret = -1;
|
||||
ret = KRB5_KPASSWD_HARDERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
@@ -87,7 +332,7 @@ int ldap_pwd_change(char *client_name, krb5_data pwd)
|
||||
ret = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version);
|
||||
if (ret != LDAP_OPT_SUCCESS) {
|
||||
fprintf(stderr, "Unable to set ldap protocol version");
|
||||
ret = -1;
|
||||
ret = KRB5_KPASSWD_HARDERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
@@ -95,20 +340,82 @@ int ldap_pwd_change(char *client_name, krb5_data pwd)
|
||||
NULL, "GSSAPI",
|
||||
NULL, NULL,
|
||||
LDAP_SASL_AUTOMATIC,
|
||||
ldap_sasl_interact, NULL);
|
||||
ldap_sasl_interact, realm_name);
|
||||
if (ret != LDAP_SUCCESS) {
|
||||
fprintf(stderr, "Unable to bind to ldap server");
|
||||
ret = -1;
|
||||
ret = KRB5_KPASSWD_HARDERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* find base dn */
|
||||
tv.tv_sec = 10;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
ret = ldap_search_ext_s(ld, "", LDAP_SCOPE_BASE,
|
||||
"objectclass=*", root_attrs, 0,
|
||||
NULL, NULL, &tv, 0, &res);
|
||||
|
||||
if (ret != LDAP_SUCCESS) {
|
||||
fprintf(stderr,
|
||||
"Search for %s on rootdse failed with error %d\n",
|
||||
root_attrs[0], ret);
|
||||
ret = KRB5_KPASSWD_HARDERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* for now just use the first result we get */
|
||||
entry = ldap_first_entry(ld, res);
|
||||
ncvals = ldap_get_values_len(ld, entry, root_attrs[0]);
|
||||
if (!ncvals) {
|
||||
fprintf(stderr, "No values for %s\n", root_attrs[0]);
|
||||
ret = KRB5_KPASSWD_HARDERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
ldap_base = strdup(ncvals[0]->bv_val);
|
||||
|
||||
ldap_value_free_len(ncvals);
|
||||
ldap_msgfree(res);
|
||||
|
||||
/* find user dn */
|
||||
ret = asprintf(&filter, "krbPrincipalName=%s", client_name);
|
||||
if (ret == -1) {
|
||||
fprintf(stderr, "Out of memory!\n");
|
||||
ret = KRB5_KPASSWD_HARDERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
tv.tv_sec = 10;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
ret = ldap_search_ext_s(ld, ldap_base, LDAP_SCOPE_SUBTREE,
|
||||
filter, attrs, 1, NULL, NULL, &tv, 0, &res);
|
||||
|
||||
if (ret != LDAP_SUCCESS) {
|
||||
fprintf(stderr, "Search for %s failed with error %d\n",
|
||||
filter, ret);
|
||||
ret = KRB5_KPASSWD_HARDERROR;
|
||||
goto done;
|
||||
}
|
||||
free(filter);
|
||||
|
||||
/* for now just use the first result we get */
|
||||
entry = ldap_first_entry(ld, res);
|
||||
userdn = ldap_get_dn(ld, entry);
|
||||
|
||||
ldap_msgfree(res);
|
||||
|
||||
if (!userdn) {
|
||||
fprintf(stderr, "No userdn, can't change password!\n");
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* build password change control */
|
||||
ctrl = ber_alloc_t(LBER_USE_DER);
|
||||
if (!ctrl) {
|
||||
fprintf(stderr, "Out of memory!\n");
|
||||
ret = -1;
|
||||
ret = KRB5_KPASSWD_HARDERROR;
|
||||
goto done;
|
||||
}
|
||||
ber_printf(ctrl, "{tstON}",
|
||||
@@ -122,12 +429,27 @@ int ldap_pwd_change(char *client_name, krb5_data pwd)
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* perform poassword change */
|
||||
ret = ldap_extended_operation(ld, LDAP_EXOP_MODIFY_PASSWD,
|
||||
&control, NULL, NULL, &id);
|
||||
/* perform password change */
|
||||
ret = ldap_extended_operation_s(ld, LDAP_EXOP_MODIFY_PASSWD, &control,
|
||||
NULL, NULL, &retoid, &retdata);
|
||||
|
||||
if (ret != LDAP_SUCCESS) {
|
||||
fprintf(stderr, "password change failed!\n");
|
||||
ret = KRB5_KPASSWD_HARDERROR;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* TODO: interpret retdata so that we can give back meaningful errors */
|
||||
|
||||
done:
|
||||
if (userdn) free(userdn);
|
||||
if (ctrl) ber_free(ctrl, 1);
|
||||
if (ld)
|
||||
if (ld) ldap_unbind(ld);
|
||||
if (ldap_uri) free(ldap_uri);
|
||||
if (tmpfile) {
|
||||
unlink(tmpfile);
|
||||
free(tmpfile);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -149,7 +471,7 @@ void handle_krb_packets(uint8_t *buf, ssize_t buflen,
|
||||
socklen_t addrlen;
|
||||
size_t reqlen;
|
||||
size_t verno;
|
||||
char *client_name;
|
||||
char *client_name, *realm_name;
|
||||
char *result_string;
|
||||
int result_err;
|
||||
uint8_t *reply;
|
||||
@@ -161,6 +483,7 @@ void handle_krb_packets(uint8_t *buf, ssize_t buflen,
|
||||
krep.length = 0;
|
||||
krep.data = NULL;
|
||||
kprincpw = NULL;
|
||||
context = NULL;
|
||||
ticket = NULL;
|
||||
lkaddr = NULL;
|
||||
|
||||
@@ -210,6 +533,14 @@ void handle_krb_packets(uint8_t *buf, ssize_t buflen,
|
||||
goto done;
|
||||
}
|
||||
|
||||
krberr = krb5_get_default_realm(context, &realm_name);
|
||||
if (krberr) {
|
||||
result_string = "Failed to get default realm name";
|
||||
result_err = KRB5_KPASSWD_HARDERROR;
|
||||
fprintf(stderr, "%s\n", result_string);
|
||||
goto done;
|
||||
}
|
||||
|
||||
krberr = krb5_auth_con_init(context, &auth_context);
|
||||
if (krberr) {
|
||||
result_string = "Unable to init auth context";
|
||||
@@ -317,11 +648,13 @@ void handle_krb_packets(uint8_t *buf, ssize_t buflen,
|
||||
client_name, kdec.length, kdec.data);
|
||||
}
|
||||
|
||||
err = ldap_pwd_change(client_name, kdec);
|
||||
|
||||
/* ok we are done, and the password change was successful! */
|
||||
result_err = KRB5_KPASSWD_SUCCESS;
|
||||
result_string = "";
|
||||
/* Actually try to change the password */
|
||||
result_err = ldap_pwd_change(client_name, realm_name, kdec);
|
||||
if (result_err != KRB5_KPASSWD_SUCCESS) {
|
||||
result_string = "Generic error occurred while changing password";
|
||||
} else {
|
||||
result_string = "";
|
||||
}
|
||||
|
||||
/* make sure password is cleared off before we free the memory */
|
||||
memset(kdec.data, 0, kdec.length);
|
||||
@@ -424,19 +757,21 @@ done:
|
||||
if (ticket) krb5_free_ticket(context, ticket);
|
||||
if (kdec.length) free(kdec.data);
|
||||
if (lkaddr) krb5_free_addresses(context, lkaddr);
|
||||
krb5_free_context(context);
|
||||
if (context) krb5_free_context(context);
|
||||
}
|
||||
|
||||
pid_t handle_conn(int fd, int type)
|
||||
{
|
||||
int mfd;
|
||||
pid_t pid;
|
||||
char address[INET6_ADDRSTRLEN+1];
|
||||
uint8_t request[1500];
|
||||
ssize_t reqlen;
|
||||
uint8_t *reply;
|
||||
ssize_t replen;
|
||||
struct sockaddr_in from;
|
||||
socklen_t fromlen;
|
||||
ssize_t sendret;
|
||||
|
||||
fromlen = sizeof(from);
|
||||
|
||||
@@ -462,16 +797,29 @@ pid_t handle_conn(int fd, int type)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!inet_ntop(from.sin_family, &from.sin_addr,
|
||||
address, sizeof(address))) {
|
||||
address[0] = '\0';
|
||||
}
|
||||
|
||||
if (debug > 0) {
|
||||
uint32_t host = ntohl(from.sin_addr.s_addr);
|
||||
uint16_t port = ntohs(from.sin_port);
|
||||
fprintf(stderr,
|
||||
"Connection from %d.%d.%d.%d:%d\n",
|
||||
(host & 0xff000000) >> 24,
|
||||
(host & 0x00ff0000) >> 16,
|
||||
(host & 0x0000ff00) >> 8,
|
||||
host & 0x000000ff,
|
||||
port);
|
||||
|
||||
fprintf(stderr, "Connection from %s:%d\n", address, port);
|
||||
}
|
||||
|
||||
/* Check blacklist for requests frm the same IP until operations
|
||||
* are finished on the active client.
|
||||
* the password change may be slow and pam_krb5 sends up to 3 UDP
|
||||
* requests waiting 1 sec. each time.
|
||||
* We do not want to start 3 password changes at the same time */
|
||||
|
||||
if (check_blacklist(address)) {
|
||||
if (debug > 0) {
|
||||
fprintf(stderr, "[%s] blacklisted\n", address);
|
||||
}
|
||||
if (type == KPASSWD_TCP) close(mfd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 1
|
||||
@@ -485,23 +833,30 @@ pid_t handle_conn(int fd, int type)
|
||||
}
|
||||
if (pid != 0) { /* parent */
|
||||
if (type == KPASSWD_TCP) close(mfd);
|
||||
add_blacklist(pid, address);
|
||||
return pid;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* children */
|
||||
handle_krb_packets(request, reqlen, &from, &reply, &replen);
|
||||
|
||||
if (replen) { /* we have something to reply */
|
||||
if (type == KPASSWD_TCP) {
|
||||
sendto(mfd, reply, replen, 0, NULL, 0);
|
||||
sendret = sendto(mfd, reply, replen, 0, NULL, 0);
|
||||
} else {
|
||||
sendto(mfd, reply, replen, 0, (struct sockaddr *)&from, fromlen);
|
||||
sendret = sendto(mfd, reply, replen, 0, (struct sockaddr *)&from, fromlen);
|
||||
}
|
||||
if (sendret == -1) {
|
||||
fprintf(stderr, "Error sending reply (%d)\n", errno);
|
||||
}
|
||||
}
|
||||
close(mfd);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* TODO: make this IPv6 aware */
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct sockaddr_in addr;
|
||||
@@ -589,14 +944,18 @@ int main(int argc, char *argv[])
|
||||
/* now that sockets are set up, enter the select loop */
|
||||
|
||||
while (1) {
|
||||
int cstatus;
|
||||
struct timeval tv;
|
||||
int cstatus, cid;
|
||||
fd_set rfd;
|
||||
|
||||
tv.tv_sec = 3;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
FD_ZERO(&rfd);
|
||||
FD_SET(udp_s, &rfd);
|
||||
FD_SET(tcp_s, &rfd);
|
||||
|
||||
ret = select(udp_s+1, &rfd, NULL, NULL, NULL);
|
||||
ret = select(udp_s+1, &rfd, NULL, NULL, &tv);
|
||||
|
||||
switch(ret) {
|
||||
case 0:
|
||||
@@ -618,12 +977,12 @@ int main(int argc, char *argv[])
|
||||
handle_conn(udp_s, KPASSWD_UDP);
|
||||
break;
|
||||
}
|
||||
/* what else?? */
|
||||
fprintf(stderr, "Select returned but no fd ready\n");
|
||||
exit(6);
|
||||
}
|
||||
|
||||
/* check for children exiting */
|
||||
waitpid(-1, &cstatus, WNOHANG);
|
||||
cid = waitpid(-1, &cstatus, WNOHANG);
|
||||
if (cid != -1 && cid != 0) {
|
||||
remove_blacklist(cid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user