#include <k5-int.h>
#include <k5-hex.h>
#include "kdb5_ldap_util.h"
#include "kdb5_ldap_list.h"
static krb5_error_code
get_conf_service_file(profile_t profile, const char *realm, char **path_out)
{
char *subsection, *path;
long ret;
*path_out = NULL;
ret = profile_get_string(profile, KDB_REALM_SECTION, realm,
KDB_MODULE_POINTER, realm, &subsection);
if (ret)
return ret;
ret = profile_get_string(profile, KDB_MODULE_SECTION, subsection,
KRB5_CONF_LDAP_SERVICE_PASSWORD_FILE, NULL,
&path);
profile_release_string(subsection);
if (ret)
return ret;
if (path == NULL) {
ret = profile_get_string(profile, KDB_MODULE_DEF_SECTION,
KRB5_CONF_LDAP_SERVICE_PASSWORD_FILE, NULL,
NULL, &path);
if (ret)
return ret;
}
if (path == NULL) {
k5_setmsg(util_context, ENOENT,
_("ldap_service_password_file not configured"));
return ENOENT;
}
*path_out = path;
return 0;
}
void
kdb5_ldap_stash_service_password(int argc, char **argv)
{
int ret = 0;
unsigned int passwd_len = 0;
char *me = progname;
char *service_object = NULL;
char *file_name = NULL, *tmp_file = NULL;
char passwd[MAX_SERVICE_PASSWD_LEN];
char *str = NULL, *hexpasswd = NULL;
char line[MAX_LEN];
FILE *pfile = NULL;
krb5_boolean print_usage = FALSE;
mode_t old_mode = 0;
if (argc != 2 && argc != 4) {
print_usage = TRUE;
goto cleanup;
}
if (argc == 4) {
if (strcmp (argv[1], "-f") == 0) {
if (((file_name = strdup (argv[2])) == NULL) ||
((service_object = strdup (argv[3])) == NULL)) {
com_err(me, ENOMEM,
_("while setting service object password"));
goto cleanup;
}
} else if (strcmp (argv[2], "-f") == 0) {
if (((file_name = strdup (argv[3])) == NULL) ||
((service_object = strdup (argv[1])) == NULL)) {
com_err(me, ENOMEM,
_("while setting service object password"));
goto cleanup;
}
} else {
print_usage = TRUE;
goto cleanup;
}
} else {
service_object = strdup (argv[1]);
if (service_object == NULL) {
com_err(me, ENOMEM, _("while setting service object password"));
goto cleanup;
}
ret = get_conf_service_file(util_context->profile,
util_context->default_realm, &file_name);
if (ret) {
com_err(me, ret, _("while getting service password filename"));
goto cleanup;
}
}
{
char prompt1[256], prompt2[256];
memset(passwd, 0, sizeof (passwd));
passwd_len = sizeof (passwd);
snprintf(prompt1, sizeof(prompt1), _("Password for \"%s\""),
service_object);
snprintf(prompt2, sizeof(prompt2), _("Re-enter password for \"%s\""),
service_object);
ret = krb5_read_password(util_context, prompt1, prompt2, passwd, &passwd_len);
if (ret != 0) {
com_err(me, ret, _("while setting service object password"));
memset(passwd, 0, sizeof (passwd));
goto cleanup;
}
if (passwd_len == 0) {
printf(_("%s: Invalid password\n"), me);
memset(passwd, 0, MAX_SERVICE_PASSWD_LEN);
goto cleanup;
}
}
ret = k5_hex_encode(passwd, passwd_len, FALSE, &hexpasswd);
zap(passwd, passwd_len);
if (ret != 0) {
com_err(me, ret, _("Failed to convert the password to hexadecimal"));
goto cleanup;
}
old_mode = umask(0177);
pfile = fopen(file_name, "a+");
if (pfile == NULL) {
com_err(me, errno, _("Failed to open file %s: %s"), file_name,
strerror (errno));
goto cleanup;
}
set_cloexec_file(pfile);
rewind (pfile);
umask(old_mode);
while (fgets (line, MAX_LEN, pfile) != NULL) {
if ((str = strstr (line, service_object)) != NULL) {
if (line [strlen (service_object)] == '#')
break;
str = NULL;
}
}
if (str == NULL) {
if (feof(pfile)) {
if (fprintf(pfile, "%s#{HEX}%s\n", service_object, hexpasswd) < 0) {
com_err(me, errno,
_("Failed to write service object password to file"));
fclose(pfile);
goto cleanup;
}
} else {
com_err(me, errno,
_("Error reading service object password file"));
fclose(pfile);
goto cleanup;
}
fclose(pfile);
} else {
FILE *newfile;
mode_t omask;
if (asprintf(&tmp_file,"%s.tmp",file_name) < 0) {
com_err(me, ENOMEM, _("while setting service object password"));
fclose(pfile);
goto cleanup;
}
omask = umask(077);
newfile = fopen(tmp_file, "w");
umask (omask);
if (newfile == NULL) {
com_err(me, errno, _("Error creating file %s"), tmp_file);
fclose(pfile);
goto cleanup;
}
set_cloexec_file(newfile);
fseek(pfile, 0, SEEK_SET);
while (fgets(line, MAX_LEN, pfile) != NULL) {
if (((str = strstr(line, service_object)) != NULL) &&
(line[strlen(service_object)] == '#')) {
if (fprintf(newfile, "%s#{HEX}%s\n", service_object, hexpasswd) < 0) {
com_err(me, errno, _("Failed to write service object "
"password to file"));
fclose(newfile);
unlink(tmp_file);
fclose(pfile);
goto cleanup;
}
} else {
if (fprintf (newfile, "%s", line) < 0) {
com_err(me, errno, _("Failed to write service object "
"password to file"));
fclose(newfile);
unlink(tmp_file);
fclose(pfile);
goto cleanup;
}
}
}
if (!feof(pfile)) {
com_err(me, errno,
_("Error reading service object password file"));
fclose(newfile);
unlink(tmp_file);
fclose(pfile);
goto cleanup;
}
fclose(pfile);
fclose(newfile);
ret = rename(tmp_file, file_name);
if (ret != 0) {
com_err(me, errno,
_("Failed to write service object password to file"));
goto cleanup;
}
}
ret = 0;
cleanup:
zapfreestr(hexpasswd);
if (service_object)
free(service_object);
profile_release_string(file_name);
if (tmp_file)
free(tmp_file);
if (print_usage)
usage();
if (ret)
exit_status++;
}