#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <strings.h>
#include <pwd.h>
#include <shadow.h>
#include <netdb.h>
#include <mp.h>
#include <rpcsvc/nis.h>
#include <rpc/key_prot.h>
#include <nsswitch.h>
#include <ns_sldap.h>
extern char *crypt();
extern long random();
extern char *getpassphrase();
extern char *program_name;
static const char *CRED_TABLE = "cred.org_dir";
#define ROOTKEY_FILE "/etc/.rootkey"
#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN 256
#endif
#define PK_FILES 1
#define PK_YP 2
#define PK_LDAP 4
#define LDAP_BINDDN_DEFAULT "cn=Directory Manager"
#define PROMPTGET_SUCCESS 1
#define PROMPTGET_FAIL -1
#define PROMPTGET_MEMORY_FAIL -2
#define PASSWD_UNMATCHED -3
#define FREE_CREDINFO(s) \
if ((s)) { (void) memset((s), 0, strlen((s))); }
#define DEF_ACTION {__NSW_RETURN, __NSW_RETURN, __NSW_CONTINUE, __NSW_CONTINUE}
static struct __nsw_lookup lookup_files = {"files", DEF_ACTION, NULL, NULL},
lookup_nis = {"nis", DEF_ACTION, NULL, &lookup_files};
static struct __nsw_switchconfig publickey_default =
{0, "publickey", 2, &lookup_nis};
static int get_ldap_bindDN(char **);
static int get_ldap_bindPassword(char **);
static int
get_ldap_bindDN(char **ret_bindDN)
{
char bindDN[BUFSIZ];
char prompt[BUFSIZ];
int blen, pos;
(void) memset(bindDN, 0, BUFSIZ);
(void) snprintf(prompt, BUFSIZ,
"\nThe LDAP bind DN and password are required for this update.\n"
"If you are not sure what values to enter, please contact your\n"
"LDAP administrator.\n\nPlease enter LDAP bind DN [%s]: ",
LDAP_BINDDN_DEFAULT);
printf(prompt);
if (fgets(bindDN, sizeof (bindDN), stdin) == NULL) {
(void) strlcpy(bindDN, LDAP_BINDDN_DEFAULT, BUFSIZ);
}
blen = strlen(bindDN);
if ((blen > 0) && (bindDN[blen - 1] == '\n')) {
bindDN[blen - 1] = '\0';
blen -= 1;
}
if (blen > 0) {
for (pos = blen - 1; pos >= 0; pos--) {
if (isspace(bindDN[pos]))
bindDN[pos] = '\0';
else
break;
}
}
if (strlen(bindDN) == 0)
(void) strlcpy(bindDN, LDAP_BINDDN_DEFAULT, BUFSIZ);
if ((*ret_bindDN = (char *)malloc(strlen(bindDN)+1)) == NULL) {
(void) memset(bindDN, 0, BUFSIZ);
return (PROMPTGET_MEMORY_FAIL);
}
(void) strlcpy(*ret_bindDN, bindDN, strlen(bindDN)+1);
(void) memset(bindDN, 0, BUFSIZ);
return (PROMPTGET_SUCCESS);
}
static int
get_ldap_bindPassword(char **ret_bindPass)
{
char bindPassword[BUFSIZ];
char prompt[BUFSIZ];
char *bindPass = NULL;
(void) memset(bindPassword, 0, BUFSIZ);
*ret_bindPass = NULL;
(void) snprintf(prompt, BUFSIZ,
"Please enter LDAP bind password: ");
bindPass = getpassphrase(prompt);
if (bindPass == NULL)
return (PROMPTGET_FAIL);
(void) strlcpy(bindPassword, bindPass, BUFSIZ);
(void) memset(bindPass, 0, strlen(bindPass));
bindPass = NULL;
(void) snprintf(prompt, BUFSIZ,
"Re-enter LDAP bind password to confirm: ");
bindPass = getpassphrase(prompt);
if (bindPass == NULL) {
(void) memset(bindPassword, 0, BUFSIZ);
return (PASSWD_UNMATCHED);
}
if (strcmp(bindPass, bindPassword) != 0) {
(void) memset(bindPassword, 0, BUFSIZ);
(void) memset(bindPass, 0, strlen(bindPass));
return (PASSWD_UNMATCHED);
} else {
(void) memset(bindPass, 0, strlen(bindPass));
if ((*ret_bindPass = (char *)malloc(strlen(bindPassword)+1))
== NULL) {
(void) memset(bindPassword, 0, BUFSIZ);
return (PROMPTGET_MEMORY_FAIL);
}
(void) strlcpy(*ret_bindPass, bindPassword,
strlen(bindPassword)+1);
(void) memset(bindPassword, 0, BUFSIZ);
return (PROMPTGET_SUCCESS);
}
}
char *
switch_policy_str(struct __nsw_switchconfig *conf)
{
struct __nsw_lookup *look;
static char policy[256];
int previous = 0;
memset((char *)policy, 0, 256);
for (look = conf->lookups; look; look = look->next) {
if (previous)
strcat(policy, " ");
strcat(policy, look->service_name);
previous = 1;
}
return (policy);
}
int
no_switch_policy(struct __nsw_switchconfig *conf)
{
return (conf == NULL || conf->lookups == NULL);
}
int
is_switch_policy(struct __nsw_switchconfig *conf, char *target)
{
return (conf &&
conf->lookups &&
strcmp(conf->lookups->service_name, target) == 0 &&
conf->lookups->next == NULL);
}
char *
first_and_only_switch_policy(char *policy,
struct __nsw_switchconfig *default_conf, char *head_msg)
{
struct __nsw_switchconfig *conf;
enum __nsw_parse_err perr;
int policy_correct = 1;
char *target_service = 0;
int use_default = 0;
if (default_conf == 0)
default_conf = &publickey_default;
conf = __nsw_getconfig(policy, &perr);
if (no_switch_policy(conf)) {
use_default = 1;
conf = default_conf;
}
target_service = conf->lookups->service_name;
if (conf->lookups->next != NULL) {
policy_correct = 0;
if (use_default) {
(void) fprintf(stderr,
"\n%s\n There is no publickey entry in %s.\n",
head_msg, __NSW_CONFIG_FILE);
(void) fprintf(stderr,
"The default publickey policy is \"publickey: %s\".\n",
switch_policy_str(default_conf));
} else
(void) fprintf(stderr,
"\n%s\nThe publickey entry in %s is \"publickey: %s\".\n",
head_msg, __NSW_CONFIG_FILE,
switch_policy_str(conf));
}
if (policy_correct == 0)
(void) fprintf(stderr,
"I cannot figure out which publickey database you want to update.\n");
if (!use_default && conf)
__nsw_freeconfig(conf);
if (policy_correct)
return (target_service);
else
return (0);
}
int
check_switch_policy(char *policy, char *target_service,
struct __nsw_switchconfig *default_conf, char *head_msg, char *tail_msg)
{
struct __nsw_switchconfig *conf;
enum __nsw_parse_err perr;
int policy_correct = 1;
if (default_conf == 0)
default_conf = &publickey_default;
conf = __nsw_getconfig(policy, &perr);
if (no_switch_policy(conf)) {
if (!is_switch_policy(default_conf, target_service)) {
(void) fprintf(stderr,
"\n%s\nThere is no publickey entry in %s.\n",
head_msg, __NSW_CONFIG_FILE);
(void) fprintf(stderr,
"The default publickey policy is \"publickey: %s\".\n",
switch_policy_str(default_conf));
policy_correct = 0;
}
} else if (!is_switch_policy(conf, target_service)) {
(void) fprintf(stderr,
"\n%s\nThe publickey entry in %s is \"publickey: %s\".\n",
head_msg, __NSW_CONFIG_FILE,
switch_policy_str(conf));
policy_correct = 0;
}
if (policy_correct == 0)
(void) fprintf(stderr,
"It should be \"publickey: %s\"%s\n\n",
target_service, tail_msg);
if (conf)
__nsw_freeconfig(conf);
return (policy_correct);
}
int
get_pk_source(char *pk_service)
{
int db = 0, got_from_switch = 0;
if (pk_service == 0) {
pk_service = first_and_only_switch_policy("publickey", 0,
"ERROR:");
if (pk_service == 0)
return (0);
(void) fprintf(stdout,
"Updating %s publickey database.\n",
pk_service);
got_from_switch = 1;
}
if (strcmp(pk_service, "ldap") == 0)
db = PK_LDAP;
else if (strcmp(pk_service, "nis") == 0)
db = PK_YP;
else if (strcmp(pk_service, "files") == 0)
db = PK_FILES;
else return (0);
if (got_from_switch == 0)
check_switch_policy("publickey", pk_service, 0, "WARNING:",
db == PK_FILES ? "" :
"; add 'files' if you want the 'nobody' key.");
return (db);
}
int
keylogin(char *netname, char *secret)
{
struct key_netstarg netst;
netst.st_pub_key[0] = 0;
memcpy(netst.st_priv_key, secret, HEXKEYBYTES);
netst.st_netname = netname;
#ifdef NFS_AUTH
nra.authtype = AUTH_DES;
nra.uid = getuid();
if (_nfssys(NFS_REVAUTH, &nra) < 0) {
perror("Warning: NFS credentials not destroyed");
err = 1;
}
#endif
if (key_setnet(&netst) < 0) {
(void) fprintf(stderr,
"Could not set %s's secret key\n", netname);
(void) fprintf(stderr, "May be the keyserv is down?\n");
return (0);
}
return (1);
}
nis_object *
init_entry()
{
static nis_object obj;
static entry_col cred_data[10];
entry_obj *eo;
memset((char *)(&obj), 0, sizeof (obj));
memset((char *)(cred_data), 0, sizeof (entry_col) * 10);
obj.zo_name = "cred";
obj.zo_group = "";
obj.zo_ttl = 43200;
obj.zo_data.zo_type = NIS_ENTRY_OBJ;
eo = &(obj.EN_data);
eo->en_type = "cred_tbl";
eo->en_cols.en_cols_val = cred_data;
eo->en_cols.en_cols_len = 5;
cred_data[4].ec_flags |= EN_CRYPT;
return (&obj);
}
static char *attrFilter[] = {
"objectclass",
"nispublickey",
"nissecretkey",
(char *)NULL
};
static int
ldap_keyobj_exist(ns_ldap_entry_t *entry)
{
char **fattrs;
fattrs = __ns_ldap_getAttr(entry, "objectClass");
if (fattrs == NULL)
return (1);
while (*fattrs) {
if (strcasecmp("NisKeyObject", *fattrs) == 0)
return (1);
fattrs++;
}
return (0);
}
static char *keyAttrs[] = {
"nispublickey",
"nissecretkey",
NULL
};
static int
ldap_attr_mod(ns_ldap_entry_t *entry, char *mechname, char *public,
ns_ldap_attr_t **pkeyattrs, char *crypt, ns_ldap_attr_t **ckeyattrs)
{
char **alist[2];
char *keys[2];
char *mechfilter;
int mechfilterlen;
int q = 0;
int i, j;
int keycount[] = {0, 0};
ns_ldap_attr_t *attrs;
keys[0] = public;
keys[1] = crypt;
mechfilter = (char *)malloc(strlen(mechname) + 3);
if (mechfilter == NULL)
return (0);
sprintf(mechfilter, "{%s}", mechname);
mechfilterlen = strlen(mechfilter);
for (q = 0; keyAttrs[q] != NULL; q++) {
int found = 0;
for (i = 0; i < entry->attr_count; i++) {
int rep = 0;
ns_ldap_attr_t *attr = entry->attr_pair[i];
char *name = attr->attrname;
int count = 0;
if (strcasecmp(keyAttrs[q], name) == 0) {
found++;
count = attr->value_count;
alist[q] = (char **)malloc(sizeof (char *) * (count + 1));
if (alist[q] == NULL)
return (0);
alist[q][attr->value_count] = NULL;
for (j = 0; j < attr->value_count; j++) {
char *val = attr->attrvalue[j];
if (strncasecmp(val, mechfilter,
mechfilterlen) == 0) {
rep++;
alist[q][j] = keys[q];
} else
alist[q][j] = val;
++keycount[q];
}
if (!rep) {
alist[q] = (char **)realloc(alist[q],
sizeof (char *) * (count + 2));
if (alist[q] == NULL)
return (0);
alist[q][attr->value_count + 1] = NULL;
alist[q][attr->value_count] = keys[q];
++keycount[q];
}
}
}
if (!found) {
alist[q] = (char **)malloc(sizeof (char *) * 2);
if (alist[q] == NULL)
return (0);
alist[q][0] = keys[q];
alist[q][1] = NULL;
++keycount[q];
}
}
if ((attrs = (ns_ldap_attr_t *)calloc(1,
sizeof (ns_ldap_attr_t))) == NULL)
return (0);
attrs->attrname = "nisPublicKey";
attrs->attrvalue = alist[0];
attrs->value_count = keycount[0];
*pkeyattrs = attrs;
if ((attrs = (ns_ldap_attr_t *)calloc(1,
sizeof (ns_ldap_attr_t))) == NULL)
return (0);
attrs->attrname = "nisSecretKey";
attrs->attrvalue = alist[1];
attrs->value_count = keycount[1];
*ckeyattrs = attrs;
return (1);
}
static void
update_ldap_attr(const char *dn, ns_ldap_attr_t **attrs, const char *passwd,
int add, int update4host, const char *bindDN, const char *bindPasswd)
{
int ldaprc;
int authstried = 0;
char *msg;
char *ldap_pw;
char **certpath = NULL;
ns_auth_t **app;
ns_auth_t **authpp = NULL;
ns_auth_t *authp = NULL;
ns_cred_t *credp;
ns_ldap_error_t *errorp = NULL;
int status;
if ((credp = (ns_cred_t *)calloc(1, sizeof (ns_cred_t))) == NULL) {
fprintf(stderr, "Can not allocate cred buffer.\n");
goto out;
}
if (update4host)
credp->cred.unix_cred.userID = strdup(bindDN);
else
credp->cred.unix_cred.userID = strdup(dn);
if (credp->cred.unix_cred.userID == NULL) {
fprintf(stderr, "Memory allocation failure (userID)\n");
goto out;
}
if (update4host) {
credp->cred.unix_cred.passwd = strdup(bindPasswd);
} else {
if (passwd)
credp->cred.unix_cred.passwd = strdup(passwd);
else {
status = get_ldap_bindPassword(&ldap_pw);
if (status != PROMPTGET_SUCCESS) {
if (!ldap_pw)
free(ldap_pw);
goto out;
}
credp->cred.unix_cred.passwd = ldap_pw;
}
}
if (credp->cred.unix_cred.passwd == NULL) {
fprintf(stderr, "Memory allocation failure (passwd)\n");
goto out;
}
if (__ns_ldap_getParam(NS_LDAP_HOST_CERTPATH_P,
(void ***)&certpath, &errorp) != NS_LDAP_SUCCESS)
goto out;
if (certpath && *certpath)
credp->hostcertpath = *certpath;
if (__ns_ldap_getServiceAuthMethods("keyserv", &authpp, &errorp) !=
NS_LDAP_SUCCESS)
goto out;
if (authpp == NULL) {
if (__ns_ldap_getParam(NS_LDAP_AUTH_P, (void ***)&authpp,
&errorp) != NS_LDAP_SUCCESS)
goto out;
}
if (authpp == NULL) {
fprintf(stderr, "No LDAP authentication method configured.\n"
" configured.\n");
goto out;
}
for (app = authpp; *app; app++) {
authp = *app;
if (authp->type == NS_LDAP_AUTH_NONE)
continue;
authstried++;
credp->auth.type = authp->type;
credp->auth.tlstype = authp->tlstype;
credp->auth.saslmech = authp->saslmech;
credp->auth.saslopt = authp->saslopt;
if (add == TRUE)
ldaprc = __ns_ldap_addAttr("publickey", dn,
(const ns_ldap_attr_t * const *)attrs,
credp, 0, &errorp);
else
ldaprc = __ns_ldap_repAttr("publickey", dn,
(const ns_ldap_attr_t * const *)attrs,
credp, 0, &errorp);
if (ldaprc == NS_LDAP_SUCCESS) {
if (credp != NULL)
(void) __ns_ldap_freeCred(&credp);
return;
}
if ((ldaprc == NS_LDAP_INTERNAL) &&
((errorp->status == LDAP_INAPPROPRIATE_AUTH) ||
(errorp->status == LDAP_INVALID_CREDENTIALS))) {
fprintf(stderr, "LDAP authentication failed.\n");
goto out;
}
}
if (authstried == 0)
fprintf(stderr, "No legal authentication method configured.\n");
out:
if (credp != NULL) {
(void) __ns_ldap_freeCred(&credp);
}
if (errorp) {
__ns_ldap_err2str(errorp->status, &msg);
fprintf(stderr, "LDAP error: %s.\n", msg);
}
fprintf(stderr, "%s: key-pair(s) unchanged.\n", program_name);
exit(1);
}
int
ldap_update(char *mechname, char *netname, char *public, char *crypt,
char *passwd)
{
char *netnamecpy;
char *id;
char *domain;
char *dn;
char *db;
char *filter;
ns_ldap_error_t *errorp;
char *pkeyatval, *ckeyatval;
ns_ldap_result_t *res;
ns_ldap_attr_t *pattrs, *cattrs;
int update4host = FALSE;
char *bindDN = NULL;
char *bindPasswd = NULL;
int status;
if ((netnamecpy = strdup(netname)) == NULL)
return (0);
if (((id = strchr(netnamecpy, '.')) == NULL) ||
((domain = strchr(netnamecpy, '@')) == NULL))
return (0);
else {
*domain++ = '\0';
*id++ = '\0';
id = strdup(id);
if (id == NULL) {
free(netnamecpy);
fprintf(stderr, "LDAP memory error (id)\n");
return (0);
}
domain = strdup(domain);
if (domain == NULL) {
free(netnamecpy);
free(id);
fprintf(stderr, "LDAP memory error (domain)\n");
return (0);
}
free(netnamecpy);
}
if (isdigit(*id)) {
__ns_ldap_uid2dn(id, &dn, NULL, &errorp);
if (dn == NULL) {
fprintf(stderr, "Could not obtain LDAP dn\n");
fprintf(stderr, "%s: key-pair(s) unchanged.\n",
program_name);
exit(1);
}
db = "passwd";
filter = (char *)malloc(strlen(id) + 13);
if (filter)
sprintf(filter, "(uidnumber=%s)", id);
else {
fprintf(stderr, "Can not allocate filter buffer.\n");
fprintf(stderr, "%s: key-pair(s) unchanged.\n",
program_name);
exit(1);
}
} else {
update4host = TRUE;
__ns_ldap_host2dn(id, NULL, &dn, NULL, &errorp);
if (dn == NULL) {
fprintf(stderr, "Could not obtain LDAP dn\n");
fprintf(stderr, "%s: key-pair(s) unchanged.\n",
program_name);
exit(1);
}
db = "hosts";
filter = (char *)malloc(strlen(id) + 6);
if (filter)
sprintf(filter, "(cn=%s)", id);
else {
fprintf(stderr, "Can not allocate filter buffer.\n");
fprintf(stderr, "%s: key-pair(s) unchanged.\n",
program_name);
exit(1);
}
status = get_ldap_bindDN(&bindDN);
if (status != PROMPTGET_SUCCESS) {
FREE_CREDINFO(bindDN);
fprintf(stderr,
"Failed to get a valid LDAP bind DN.\n"
"%s: key-pair(s) unchanged.\n",
program_name);
exit(1);
}
status = get_ldap_bindPassword(&bindPasswd);
if (status != PROMPTGET_SUCCESS) {
FREE_CREDINFO(bindPasswd);
FREE_CREDINFO(bindDN);
fprintf(stderr,
"Failed to get a valid LDAP bind password."
"\n%s: key-pair(s) unchanged.\n",
program_name);
exit(1);
}
}
pkeyatval = (char *)malloc(strlen(mechname) + strlen(public) + 3);
if (pkeyatval == NULL) {
FREE_CREDINFO(bindPasswd);
FREE_CREDINFO(bindDN);
fprintf(stderr, "LDAP memory error (pkeyatval)\n");
fprintf(stderr, "%s: key-pair(s) unchanged.\n", program_name);
exit(1);
}
sprintf(pkeyatval, "{%s}%s", mechname, public);
ckeyatval = (char *)malloc(strlen(mechname) + strlen(crypt) + 3);
if (ckeyatval == NULL) {
FREE_CREDINFO(pkeyatval);
FREE_CREDINFO(bindPasswd);
FREE_CREDINFO(bindDN);
fprintf(stderr, "LDAP memory error (pkeyatval)\n");
fprintf(stderr, "%s: key-pair(s) unchanged.\n", program_name);
exit(1);
}
sprintf(ckeyatval, "{%s}%s", mechname, crypt);
if ((__ns_ldap_list(db, filter, NULL, (const char **)attrFilter,
NULL, 0, &res, &errorp,
NULL, NULL) == NS_LDAP_SUCCESS) && res == NULL) {
FREE_CREDINFO(ckeyatval);
FREE_CREDINFO(pkeyatval);
FREE_CREDINFO(bindPasswd);
FREE_CREDINFO(bindDN);
fprintf(stderr, "LDAP entry does not exist.\n");
fprintf(stderr, "%s: key-pair(s) unchanged.\n", program_name);
exit(1);
}
if (!ldap_keyobj_exist(&res->entry[0])) {
char **newattr;
ns_ldap_attr_t *attrs[4];
newattr = (char **)calloc(2, sizeof (char *));
newattr[0] = "NisKeyObject";
newattr[1] = NULL;
if ((attrs[0] = (ns_ldap_attr_t *)calloc(1,
sizeof (ns_ldap_attr_t))) == NULL) {
FREE_CREDINFO(ckeyatval);
FREE_CREDINFO(pkeyatval);
FREE_CREDINFO(bindPasswd);
FREE_CREDINFO(bindDN);
fprintf(stderr, "Memory allocation failed\n");
fprintf(stderr, "%s: key-pair(s) unchanged.\n",
program_name);
exit(1);
}
attrs[0]->attrname = "objectClass";
attrs[0]->attrvalue = newattr;
attrs[0]->value_count = 1;
newattr = (char **)calloc(2, sizeof (char *));
newattr[0] = pkeyatval;
newattr[1] = NULL;
if ((attrs[1] = (ns_ldap_attr_t *)calloc(1,
sizeof (ns_ldap_attr_t))) == NULL) {
FREE_CREDINFO(ckeyatval);
FREE_CREDINFO(pkeyatval);
FREE_CREDINFO(bindPasswd);
FREE_CREDINFO(bindDN);
fprintf(stderr, "Memory allocation failed\n");
fprintf(stderr, "%s: key-pair(s) unchanged.\n",
program_name);
exit(1);
}
attrs[1]->attrname = "nisPublicKey";
attrs[1]->attrvalue = newattr;
attrs[1]->value_count = 1;
newattr = (char **)calloc(2, sizeof (char *));
newattr[0] = ckeyatval;
newattr[1] = NULL;
if ((attrs[2] = (ns_ldap_attr_t *)calloc(1,
sizeof (ns_ldap_attr_t))) == NULL) {
FREE_CREDINFO(ckeyatval);
FREE_CREDINFO(pkeyatval);
FREE_CREDINFO(bindPasswd);
FREE_CREDINFO(bindDN);
fprintf(stderr, "Memory allocation failed\n");
fprintf(stderr, "%s: key-pair(s) unchanged.\n",
program_name);
exit(1);
}
attrs[2]->attrname = "nisSecretKey";
attrs[2]->attrvalue = newattr;
attrs[2]->value_count = 1;
attrs[3] = NULL;
update_ldap_attr(dn, attrs, passwd, TRUE, update4host,
bindDN, bindPasswd);
} else {
ns_ldap_attr_t *attrs[4];
if (!ldap_attr_mod(&res->entry[0], mechname,
pkeyatval, &pattrs,
ckeyatval, &cattrs)) {
FREE_CREDINFO(ckeyatval);
FREE_CREDINFO(pkeyatval);
FREE_CREDINFO(bindPasswd);
FREE_CREDINFO(bindDN);
fprintf(stderr,
"Could not generate LDAP attribute list.\n");
fprintf(stderr,
"%s: key-pair(s) unchanged.\n", program_name);
exit(1);
}
attrs[0] = pattrs;
attrs[1] = cattrs;
attrs[2] = NULL;
update_ldap_attr(dn, attrs, passwd, FALSE, update4host,
bindDN, bindPasswd);
}
FREE_CREDINFO(ckeyatval);
FREE_CREDINFO(pkeyatval);
FREE_CREDINFO(bindPasswd);
FREE_CREDINFO(bindDN);
return (0);
}