diff options
Diffstat (limited to 'ipa-server/ipa-kpasswd')
-rw-r--r-- | ipa-server/ipa-kpasswd/ipa_kpasswd.c | 349 |
1 files changed, 280 insertions, 69 deletions
diff --git a/ipa-server/ipa-kpasswd/ipa_kpasswd.c b/ipa-server/ipa-kpasswd/ipa_kpasswd.c index f5540b74c..b0020c04f 100644 --- a/ipa-server/ipa-kpasswd/ipa_kpasswd.c +++ b/ipa-server/ipa-kpasswd/ipa_kpasswd.c @@ -28,26 +28,54 @@ #define TMP_TEMPLATE "/tmp/kpasswd.XXXXXX" #define KPASSWD_PORT 464 +/* blacklist entries are released only BLCAKLIST_TIMEOUT seconds + * after the children performing the noperation has finished. + * this is to avoid races */ + +#define BLACKLIST_TIMEOUT 5 + struct blacklist { struct blacklist *next; char *address; pid_t pid; + time_t expire; }; static struct blacklist *global_blacklist = NULL; int check_blacklist(char *address) { - struct blacklist *bl; + struct blacklist *bl, *prev_bl; + time_t now = time(NULL); if (!global_blacklist) { return 0; } - for (bl = global_blacklist; bl; bl = bl->next) { + prev_bl = NULL; + bl = global_blacklist; + while (bl) { + if (bl->expire && (bl->expire < now)) { + if (prev_bl) { + prev_bl->next = bl->next; + free(bl->address); + free(bl); + bl = prev_bl->next; + } else { + global_blacklist = bl->next; + free(bl->address); + free(bl); + bl = global_blacklist; + } + continue; + } + if (strcmp(address, bl->address) == 0) { return 1; } + + prev_bl = bl; + bl = bl->next; } return 0; @@ -62,6 +90,7 @@ int add_blacklist(pid_t pid, char *address) bl->next = NULL; bl->pid = pid; + bl->expire = 0; bl->address = strdup(address); if (!bl->address) { free(bl); @@ -83,32 +112,24 @@ int add_blacklist(pid_t pid, char *address) int remove_blacklist(pid_t pid) { - struct blacklist *bl, *pbl; + struct blacklist *bl; 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); + bl->expire = time(NULL) + BLACKLIST_TIMEOUT; return 0; } - pbl = bl; bl = bl->next; } return -1; } -int debug = 1; +int debug = 0; char *srv_pri_name = "kadmin/changepw"; char *keytab_name = NULL; @@ -255,12 +276,19 @@ int ldap_sasl_interact(LDAP *ld, unsigned flags, void *priv_data, void *sit) return ret; } -int ldap_pwd_change(char *client_name, char *realm_name, krb5_data pwd) +/* from DS ldaprot.h */ +#define LDAP_TAG_PWP_WARNING 0xA0 /* context specific + constructed + 0 */ +#define LDAP_TAG_PWP_SECSLEFT 0x80L /* context specific + primitive */ +#define LDAP_TAG_PWP_GRCLOGINS 0x81L /* context specific + primitive + 1 */ +#define LDAP_TAG_PWP_ERROR 0x81L /* context specific + primitive + 1 */ + +int ldap_pwd_change(char *client_name, char *realm_name, krb5_data pwd, char **errstr) { char *tmp_file = NULL; int version; LDAP *ld = NULL; BerElement *ctrl = NULL; + BerElement *sctrl = NULL; struct berval control; struct berval newpw; char hostname[1024]; @@ -275,7 +303,12 @@ int ldap_pwd_change(char *client_name, char *realm_name, krb5_data pwd) struct berval *retdata = NULL; struct timeval tv; LDAPMessage *entry, *res = NULL; - int ret; + LDAPControl **srvctrl = NULL; + char *exterr1 = NULL; + char *exterr2 = NULL; + char *err; + int msgid; + int ret, rc; tmp_file = strdup(TMP_TEMPLATE); if (!tmp_file) { @@ -399,7 +432,12 @@ int ldap_pwd_change(char *client_name, char *realm_name, krb5_data pwd) if (ret != LDAP_SUCCESS) { syslog(LOG_ERR, "Search for %s failed with error %d", filter, ret); - ret = KRB5_KPASSWD_HARDERROR; + if (ret == LDAP_CONSTRAINT_VIOLATION) { + *errstr = strdup("Password Change Failed"); + ret = KRB5_KPASSWD_SOFTERROR; + } else { + ret = KRB5_KPASSWD_HARDERROR; + } goto done; } free(filter); @@ -409,6 +447,7 @@ int ldap_pwd_change(char *client_name, char *realm_name, krb5_data pwd) userdn = ldap_get_dn(ld, entry); ldap_msgfree(res); + res = NULL; if (!userdn) { syslog(LOG_ERR, "No userdn, can't change password!"); @@ -430,25 +469,164 @@ int ldap_pwd_change(char *client_name, char *realm_name, krb5_data pwd) ret = ber_flatten2(ctrl, &control, 0); if (ret < 0) { syslog(LOG_ERR, "ber flattening failed!"); - ret = -1; + ret = KRB5_KPASSWD_HARDERROR; goto done; } /* perform password change */ - ret = ldap_extended_operation_s(ld, LDAP_EXOP_MODIFY_PASSWD, &control, - NULL, NULL, &retoid, &retdata); - + ret = ldap_extended_operation(ld, + LDAP_EXOP_MODIFY_PASSWD, + &control, NULL, NULL, + &msgid); if (ret != LDAP_SUCCESS) { - syslog(LOG_ERR, "password change failed!"); + syslog(LOG_ERR, "ldap_extended_operation() failed. (%d)", ret); + ret = KRB5_KPASSWD_HARDERROR; + goto done; + } + + tv.tv_sec = 10; + tv.tv_usec = 0; + + ret = ldap_result(ld, msgid, 1, &tv, &res); + if (ret == -1) { + ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &rc); + syslog(LOG_ERR, "ldap_result() failed. (%d)", rc); + ret = KRB5_KPASSWD_HARDERROR; + goto done; + } + + ret = ldap_parse_extended_result(ld, res, &retoid, &retdata, 0); + if(ret != LDAP_SUCCESS) { + syslog(LOG_ERR, "ldap_parse_extended_result() failed."); + ldap_msgfree(res); + ret = KRB5_KPASSWD_HARDERROR; + goto done; + } + if (retoid || retdata) { + syslog(LOG_ERR, "ldap_parse_extended_result() returned data, but we don't handle it yet."); + } + + ret = ldap_parse_result(ld, res, &rc, NULL, &err, NULL, &srvctrl, 0); + if(ret != LDAP_SUCCESS) { + syslog(LOG_ERR, "ldap_parse_result() failed."); ret = KRB5_KPASSWD_HARDERROR; goto done; + } + if (rc != LDAP_SUCCESS) { + ret = KRB5_KPASSWD_SOFTERROR; + if (rc != LDAP_CONSTRAINT_VIOLATION) { + ret = KRB5_KPASSWD_HARDERROR; + } + } + if (err) { + syslog(LOG_ERR, "ldap_parse_result(): [%s]", err); + ldap_memfree(err); } - /* TODO: interpret retdata so that we can give back meaningful errors */ + if (srvctrl) { + + LDAPControl *pprc = NULL; + int i; + + for (i = 0; srvctrl[i]; i++) { + if (0 == strcmp(srvctrl[i]->ldctl_oid, LDAP_CONTROL_PASSWORDPOLICYRESPONSE)) { + pprc = srvctrl[i]; + } + } + if (pprc) { + sctrl = ber_init(&pprc->ldctl_value); + } + + if (sctrl) { + /* + * PasswordPolicyResponseValue ::= SEQUENCE { + * warning [0] CHOICE OPTIONAL { + * timeBeforeExpiration [0] INTEGER (0 .. maxInt), + * graceLoginsRemaining [1] INTEGER (0 .. maxInt) } + * error [1] ENUMERATED OPTIONAL { + * passwordExpired (0), + * accountLocked (1), + * changeAfterReset (2), + * passwordModNotAllowed (3), + * mustSupplyOldPassword (4), + * invalidPasswordSyntax (5), + * passwordTooShort (6), + * passwordTooYoung (7), + * passwordInHistory (8) } } + */ + + ber_tag_t rtag, btag; + ber_int_t bint; + rtag = ber_scanf(sctrl, "{t", &btag); + if (btag == LDAP_TAG_PWP_WARNING) { + rtag = ber_scanf(sctrl, "{ti}", &btag, &bint); + if (btag == LDAP_TAG_PWP_SECSLEFT) { + asprintf(&exterr2, " (%d seconds left before password expires)", bint); + } else { + asprintf(&exterr2, " (%d grace logins remaining)", bint); + } + if (!exterr2) { + syslog(LOG_ERR, "exterr2: OOM?"); + } + rtag = ber_scanf(sctrl, "t", &btag); + } + if (btag == LDAP_TAG_PWP_ERROR) { + rtag = ber_scanf(sctrl, "e", &bint); + switch(bint) { + case 0: + asprintf(&exterr1, " Err%d: Password Expired.", bint); + break; + case 1: + asprintf(&exterr1, " Err%d: Account locked.", bint); + break; + case 2: + asprintf(&exterr1, " Err%d: Password changed after reset.", bint); + break; + case 3: + asprintf(&exterr1, " Err%d: Password change not allowed.", bint); + break; + case 4: + asprintf(&exterr1, " Err%d: [Shouldn't happen].", bint); + break; + case 5: + asprintf(&exterr1, " Err%d: Password too simple.", bint); + break; + case 6: + asprintf(&exterr1, " Err%d: Password too short.", bint); + break; + case 7: + asprintf(&exterr1, " Err%d: Too soon to change password.", bint); + break; + case 8: + asprintf(&exterr1, " Err%d: Password reuse not permitted.", bint); + break; + default: + asprintf(&exterr1, " Err%d: Unknown Errorcode.", bint); + break; + } + if (!exterr1) { + syslog(LOG_ERR, "exterr1: OOM?"); + } + } + } + } + + if (ret != LDAP_SUCCESS) { + syslog(LOG_ERR, "password change failed!"); + asprintf(errstr, "Password change, Failed.%s%s", exterr1?exterr1:"", exterr2?exterr2:""); + } else { + syslog(LOG_ERR, "password change succeeded!"); + asprintf(errstr, "Password change, Succeeded.%s%s", exterr1?exterr1:"", exterr2?exterr2:""); + } done: - if (userdn) free(userdn); if (ctrl) ber_free(ctrl, 1); + if (sctrl) ber_free(sctrl, 1); + if (srvctrl) ldap_controls_free(srvctrl); + if (res) ldap_msgfree(res); + if (exterr1) free(exterr1); + if (exterr2) free(exterr2); + if (userdn) free(userdn); if (ld) ldap_unbind_ext_s(ld, NULL, NULL); if (ldap_uri) free(ldap_uri); if (tmp_file) { @@ -482,6 +660,7 @@ void handle_krb_packets(uint8_t *buf, ssize_t buflen, *replen = 0; + result_string = NULL; auth_context = NULL; krep.length = 0; krep.data = NULL; @@ -508,14 +687,14 @@ void handle_krb_packets(uint8_t *buf, ssize_t buflen, } break; default: - result_string = "Invalid remopte IP address"; + result_string = strdup("Invalid remopte IP address"); result_err = KRB5_KPASSWD_MALFORMED; syslog(LOG_ERR, "%s", result_string); goto done; } if (buflen < 4) { - result_string = "Request truncated"; + result_string = strdup("Request truncated"); result_err = KRB5_KPASSWD_MALFORMED; syslog(LOG_ERR, "%s", result_string); goto done; @@ -524,7 +703,7 @@ void handle_krb_packets(uint8_t *buf, ssize_t buflen, reqlen = (buf[0] << 8) + buf[1]; if (reqlen != buflen) { - result_string = "Unmatching request length"; + result_string = strdup("Unmatching request length"); result_err = KRB5_KPASSWD_MALFORMED; syslog(LOG_ERR, "%s", result_string); goto done; @@ -533,7 +712,7 @@ void handle_krb_packets(uint8_t *buf, ssize_t buflen, verno = (buf[2] << 8) + buf[3]; if (verno != 1) { - result_string = "Unsupported version"; + result_string = strdup("Unsupported version"); result_err = KRB5_KPASSWD_BAD_VERSION; syslog(LOG_ERR, "%s", result_string); goto done; @@ -541,7 +720,7 @@ void handle_krb_packets(uint8_t *buf, ssize_t buflen, kreq.length = (buf[4] << 8) + buf[5]; if (kreq.length > (buflen - 6)) { - result_string = "Request truncated"; + result_string = strdup("Request truncated"); result_err = KRB5_KPASSWD_MALFORMED; syslog(LOG_ERR, "%s", result_string); goto done; @@ -550,7 +729,7 @@ void handle_krb_packets(uint8_t *buf, ssize_t buflen, krberr = krb5_init_context(&context); if (krberr) { - result_string = "Failed to init kerberos context"; + result_string = strdup("Failed to init kerberos context"); result_err = KRB5_KPASSWD_HARDERROR; syslog(LOG_ERR, "%s", result_string); goto done; @@ -558,7 +737,7 @@ void handle_krb_packets(uint8_t *buf, ssize_t buflen, krberr = krb5_get_default_realm(context, &realm_name); if (krberr) { - result_string = "Failed to get default realm name"; + result_string = strdup("Failed to get default realm name"); result_err = KRB5_KPASSWD_HARDERROR; syslog(LOG_ERR, "%s", result_string); goto done; @@ -566,7 +745,7 @@ void handle_krb_packets(uint8_t *buf, ssize_t buflen, krberr = krb5_auth_con_init(context, &auth_context); if (krberr) { - result_string = "Unable to init auth context"; + result_string = strdup("Unable to init auth context"); result_err = KRB5_KPASSWD_HARDERROR; syslog(LOG_ERR, "%s: %s", result_string, krb5_get_error_message(context, krberr)); @@ -576,7 +755,7 @@ void handle_krb_packets(uint8_t *buf, ssize_t buflen, krberr = krb5_auth_con_setflags(context, auth_context, KRB5_AUTH_CONTEXT_DO_SEQUENCE); if (krberr) { - result_string = "Unable to init auth context"; + result_string = strdup("Unable to init auth context"); result_err = KRB5_KPASSWD_HARDERROR; syslog(LOG_ERR, "%s: %s", result_string, krb5_get_error_message(context, krberr)); @@ -587,7 +766,7 @@ void handle_krb_packets(uint8_t *buf, ssize_t buflen, strlen(realm_name), realm_name, "kadmin", "changepw", NULL); if (krberr) { - result_string = "Unable to build principal"; + result_string = strdup("Unable to build principal"); result_err = KRB5_KPASSWD_HARDERROR; syslog(LOG_ERR, "%s: %s", result_string, krb5_get_error_message(context, krberr)); @@ -596,7 +775,7 @@ void handle_krb_packets(uint8_t *buf, ssize_t buflen, krberr = krb5_kt_resolve(context, keytab_name, &keytab); if (krberr) { - result_string = "Unable to retrieve keytab"; + result_string = strdup("Unable to retrieve keytab"); result_err = KRB5_KPASSWD_HARDERROR; syslog(LOG_ERR, "%s: %s", result_string, krb5_get_error_message(context, krberr)); @@ -606,7 +785,7 @@ void handle_krb_packets(uint8_t *buf, ssize_t buflen, krberr = krb5_rd_req(context, &auth_context, &kreq, kprincpw, keytab, NULL, &ticket); if (krberr) { - result_string = "Unable to read request"; + result_string = strdup("Unable to read request"); result_err = KRB5_KPASSWD_AUTHERROR; syslog(LOG_ERR, "%s: %s", result_string, krb5_get_error_message(context, krberr)); @@ -618,7 +797,7 @@ void handle_krb_packets(uint8_t *buf, ssize_t buflen, * the password have been successfully changed */ krberr = krb5_mk_rep(context, auth_context, &krep); if (krberr) { - result_string = "Failed to to build reply"; + result_string = strdup("Failed to to build reply"); result_err = KRB5_KPASSWD_HARDERROR; syslog(LOG_ERR, "%s: %s", result_string, krb5_get_error_message(context, krberr)); @@ -627,7 +806,7 @@ void handle_krb_packets(uint8_t *buf, ssize_t buflen, /* verify that this is an AS_REQ ticket */ if (!(ticket->enc_part2->flags & TKT_FLG_INITIAL)) { - result_string = "Ticket must be derived from a password"; + result_string = strdup("Ticket must be derived from a password"); result_err = KRB5_KPASSWD_AUTHERROR; syslog(LOG_ERR, "%s", result_string); goto kpreply; @@ -636,7 +815,7 @@ void handle_krb_packets(uint8_t *buf, ssize_t buflen, krberr = krb5_unparse_name(context, ticket->enc_part2->client, &client_name); if (krberr) { - result_string = "Unable to parse client name"; + result_string = strdup("Unable to parse client name"); result_err = KRB5_KPASSWD_HARDERROR; syslog(LOG_ERR, "%s", result_string); goto kpreply; @@ -644,7 +823,7 @@ void handle_krb_packets(uint8_t *buf, ssize_t buflen, krberr = krb5_auth_con_setaddrs(context, auth_context, NULL, &rkaddr); if (krberr) { - result_string = "Failed to set client address"; + result_string = strdup("Failed to set client address"); result_err = KRB5_KPASSWD_HARDERROR; syslog(LOG_ERR, "%s: %s", result_string, krb5_get_error_message(context, krberr)); @@ -659,24 +838,22 @@ void handle_krb_packets(uint8_t *buf, ssize_t buflen, * requires the local address (from kadmin code) */ krberr = krb5_rd_priv(context, auth_context, &kenc, &kdec, &replay); if (krberr) { - result_string = "Failed to decrypt password"; + result_string = strdup("Failed to decrypt password"); result_err = KRB5_KPASSWD_HARDERROR; syslog(LOG_ERR, "%s: %s", result_string, krb5_get_error_message(context, krberr)); goto kpreply; } - if (debug > 0) { + if (debug > 100) { syslog(LOG_ERR, "Client %s trying to set password [%*s]", client_name, kdec.length, kdec.data); } /* 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 = ""; + result_err = ldap_pwd_change(client_name, realm_name, kdec, &result_string); + if (result_string == NULL) { + result_string = strdup("Server Error"); } /* make sure password is cleared off before we free the memory */ @@ -700,7 +877,7 @@ kpreply: /* we listen on ANYADDR, use this retrieve the right address */ krberr = krb5_os_localaddr(context, &lkaddr); if (krberr) { - result_string = "Failed to retrieve local address"; + result_string = strdup("Failed to retrieve local address"); syslog(LOG_ERR, "%s: %s", result_string, krb5_get_error_message(context, krberr)); goto done; @@ -708,7 +885,7 @@ kpreply: krberr = krb5_auth_con_setaddrs(context, auth_context, lkaddr[0], NULL); if (krberr) { - result_string = "Failed to set local address"; + result_string = strdup("Failed to set local address"); syslog(LOG_ERR, "%s: %s", result_string, krb5_get_error_message(context, krberr)); goto done; @@ -716,7 +893,7 @@ kpreply: krberr = krb5_mk_priv(context, auth_context, &kdec, &kenc, &replay); if (krberr) { - result_string = "Failed to encrypt reply message"; + result_string = strdup("Failed to encrypt reply message"); syslog(LOG_ERR, "%s: %s", result_string, krb5_get_error_message(context, krberr)); /* encryption was unsuccessful, let's return a krb error */ @@ -734,7 +911,7 @@ kpreply: krb5err.susec = 0; krberr = krb5_timeofday(context, &krb5err.stime); if (krberr) { - result_string = "Failed to set time of day"; + result_string = strdup("Failed to set time of day"); syslog(LOG_ERR, "%s: %s", result_string, krb5_get_error_message(context, krberr)); goto done; @@ -744,7 +921,7 @@ kpreply: krb5err.e_data = kdec; krberr = krb5_mk_error(context, &krb5err, &kenc); if (krberr) { - result_string = "Failed to build error message"; + result_string = strdup("Failed to build error message"); syslog(LOG_ERR, "%s: %s", result_string, krb5_get_error_message(context, krberr)); goto done; @@ -774,6 +951,7 @@ kpreply: *replen = replylen; done: + if (result_string) free(result_string); if (auth_context) krb5_auth_con_free(context, auth_context); if (kprincpw) krb5_free_principal(context, kprincpw); if (krep.length) free(krep.data); @@ -787,6 +965,7 @@ pid_t handle_conn(int fd, int type) { int mfd, tcp; pid_t pid; + char addrto6[INET6_ADDRSTRLEN+1]; char address[INET6_ADDRSTRLEN+1]; uint8_t request[1500]; ssize_t reqlen; @@ -809,17 +988,38 @@ pid_t handle_conn(int fd, int type) return -1; } } else { - mfd = fd; + /* read first to empty the buffer on udp connections */ + reqlen = recvfrom(fd, request, sizeof(request), 0, + (struct sockaddr *)&from, &fromlen); + if (reqlen <= 0) { + syslog(LOG_ERR, "Error receiving request (%d) %s", + errno, strerror(errno)); + return -1; + } + } (void) getnameinfo((struct sockaddr *)&from, fromlen, - address, INET6_ADDRSTRLEN+1, + addrto6, INET6_ADDRSTRLEN+1, NULL, 0, NI_NUMERICHOST); if (debug > 0) { - syslog(LOG_ERR, "Connection from %s", address); + syslog(LOG_ERR, "Connection from %s", addrto6); } + if (strchr(addrto6, ':') == NULL) { + char *prefix6 = "::ffff:"; + /* this is an IPv4 formatted addr + * convert to IPv6 mapped addr */ + memcpy(address, prefix6, 7); + memcpy(&address[7], addrto6, INET6_ADDRSTRLEN-7); + } else { + /* regular IPv6 address, copy as is */ + memcpy(address, addrto6, INET6_ADDRSTRLEN); + } + /* make sure we have termination */ + address[INET6_ADDRSTRLEN] = '\0'; + /* Check blacklist for requests from 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 @@ -834,15 +1034,17 @@ pid_t handle_conn(int fd, int type) return 0; } - reqlen = recvfrom(mfd, request, sizeof(request), 0, - (struct sockaddr *)&from, &fromlen); - if (reqlen <= 0) { - syslog(LOG_ERR, "Error receiving request (%d) %s", - errno, strerror(errno)); - if (tcp) close(mfd); - return -1; + /* now read data if it was a TCP connection */ + if (tcp) { + reqlen = recvfrom(mfd, request, sizeof(request), 0, + (struct sockaddr *)&from, &fromlen); + if (reqlen <= 0) { + syslog(LOG_ERR, "Error receiving request (%d) %s", + errno, strerror(errno)); + close(mfd); + return -1; + } } - #if 1 /* handle kerberos and ldap operations in childrens */ pid = fork(); @@ -860,6 +1062,7 @@ pid_t handle_conn(int fd, int type) #endif /* children */ + if (debug > 0) syslog(LOG_ERR, "Servicing %s", address); /* TCP packets prepend the lenght as a 32bit network order field, * this information seem to be just redundant, so let's simply @@ -874,13 +1077,13 @@ pid_t handle_conn(int fd, int type) if (tcp) { sendret = sendto(mfd, reply, replen, 0, NULL, 0); } else { - sendret = sendto(mfd, reply, replen, 0, (struct sockaddr *)&from, fromlen); + sendret = sendto(fd, reply, replen, 0, (struct sockaddr *)&from, fromlen); } if (sendret == -1) { syslog(LOG_ERR, "Error sending reply (%d)", errno); } } - close(mfd); + if (tcp) close(mfd); exit(0); } @@ -895,7 +1098,7 @@ int main(int argc, char *argv[]) int pfdtype[4]; int nfds; int ret; - char *key; + char *env; /* log to syslog */ openlog("kpasswd", LOG_PID, LOG_DAEMON); @@ -935,15 +1138,21 @@ int main(int argc, char *argv[]) exit(0); } - key = getenv("KRB5_KTNAME"); - if (!key) { - key = DEFAULT_KEYTAB; + /* source evn vars */ + env = getenv("KRB5_KTNAME"); + if (!env) { + env = DEFAULT_KEYTAB; } - keytab_name = strdup(key); + keytab_name = strdup(env); if (!keytab_name) { syslog(LOG_ERR, "Out of memory!"); } + env = getenv("IPA_KPASSWD_DEBUG"); + if (env) { + debug = strtol(env, NULL, 0); + } + /* set hints */ memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; @@ -1026,6 +1235,8 @@ int main(int argc, char *argv[]) /* check for children exiting */ cid = waitpid(-1, &cstatus, WNOHANG); if (cid != -1 && cid != 0) { + if (debug > 0) + syslog(LOG_ERR, "pid %d completed operations!\n", cid); remove_blacklist(cid); } } |