#include <sys/types.h>
#include <sys/stat.h>
#include <ctype.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <syslog.h>
#include <pwd.h>
#include <signal.h>
#include <crypt.h>
#include <rpc/rpc.h>
#include <rpcsvc/yppasswd.h>
#include <utmpx.h>
#include <shadow.h>
#include <ndbm.h>
#include "shim.h"
#include "yptol.h"
#include "../ldap_util.h"
extern int getdomainname(char *, int);
#define CRYPTPWSIZE CRYPT_MAXCIPHERTEXTLEN
#define STRSIZE 100
#define FINGERSIZE (4 * STRSIZE - 4)
#define SHELLSIZE (STRSIZE - 2)
#define UTUSERLEN (sizeof (((struct utmpx *)0)->ut_user))
#define COLON_CHAR ':'
#define YPDBPATH "/var/yp"
#define BYNAME ".byname"
#define BYUID ".byuid"
#define BYGID ".bygid"
#define PASSWD_MAPPING "passwd" BYNAME
#define PASSWD_ADJUNCT_MAPPING "passwd.adjunct" BYNAME
#define AGEING_MAPPING "ageing" BYNAME
#define CNG_PASSWD 0x0001
#define CNG_SH 0x0002
#define CNG_GECOS 0x0004
extern int single, nogecos, noshell, nopw, mflag;
struct passwd_entry {
char *pw_name;
char *pw_passwd;
char *pw_uid;
char *pw_gid;
char *pw_gecos;
char *pw_dir;
char *pw_shell;
char *adjunct_tail;
bool_t adjunct;
char *pwd_str;
char *adjunct_str;
};
extern bool_t validloginshell(char *sh, char *arg, int);
extern int validstr(char *str, size_t size);
suc_code write_shadow_info(char *, struct spwd *);
int put_new_info(struct passwd_entry *, char *);
char *create_pwd_str(struct passwd_entry *, bool_t);
int proc_domain(struct yppasswd *, bool_t, char *);
int proc_request(struct yppasswd *, struct passwd_entry *, bool_t, char *);
int modify_ent(struct yppasswd *, struct passwd_entry *t, bool_t, char *);
int get_change_list(struct yppasswd *, struct passwd_entry *);
struct passwd_entry *get_old_info(char *, char *);
static char *get_next_token(char *, char **, char *);
void free_pwd_entry(struct passwd_entry *);
struct spwd *get_old_shadow(char *, char *);
suc_code decode_shadow_entry(datum *, struct spwd *);
void free_shadow_entry(struct spwd *);
int proc_maps(char *, struct passwd_entry *);
int proc_map_list(char **, char *, struct passwd_entry *, bool_t);
int update_single_map(char *, struct passwd_entry *, bool_t);
bool_t strend(char *s1, char *s2);
void
shim_changepasswd(SVCXPRT *transp)
{
struct yppasswd yppwd;
bool_t root_on_master = FALSE;
char domain[MAXNETNAMELEN+1];
char **domain_list;
int dom_count, i;
int ret, ans = 2;
memset(&yppwd, 0, sizeof (struct yppasswd));
if (!svc_getargs(transp, xdr_yppasswd, (caddr_t)&yppwd)) {
svcerr_decode(transp);
return;
}
if ((!validstr(yppwd.newpw.pw_passwd, CRYPTPWSIZE)) ||
(!validstr(yppwd.newpw.pw_name, UTUSERLEN)) ||
(!validstr(yppwd.newpw.pw_gecos, FINGERSIZE)) ||
(!validstr(yppwd.newpw.pw_shell, SHELLSIZE))) {
svcerr_decode(transp);
return;
}
if (strcmp(transp->xp_netid, "ticlts") == 0) {
svc_local_cred_t cred;
if (!svc_get_local_cred(transp, &cred)) {
logmsg(MSG_NOTIMECHECK, LOG_ERR,
"Couldn't get local user credentials");
} else if (cred.ruid == 0)
root_on_master = TRUE;
}
if (0 !=
(dom_count = get_mapping_yppasswdd_domain_list(&domain_list))) {
for (i = 0; i < dom_count; i ++) {
ret = proc_domain(&yppwd, root_on_master,
domain_list[i]);
if (0 != ans)
ans = ret;
}
}
else
{
if (0 > getdomainname(domain, MAXNETNAMELEN+1)) {
logmsg(MSG_NOTIMECHECK, LOG_ERR,
"Could not get any domain info");
} else {
ans = proc_domain(&yppwd, root_on_master, domain);
}
}
if (!svc_sendreply(transp, xdr_int, (char *)&ans))
logmsg(MSG_NOTIMECHECK, LOG_WARNING,
"could not reply to RPC call");
}
int
proc_domain(struct yppasswd *yppwd, bool_t root_on_master, char *domain)
{
struct passwd_entry *old_pwd;
char *p;
int ans = 2;
for (p = yppwd->newpw.pw_name; (*p != '\0'); p++)
if ((*p == ':') || !(isprint(*p)))
*p = '$';
for (p = yppwd->newpw.pw_passwd; (*p != '\0'); p++)
if ((*p == ':') || !(isprint(*p)))
*p = '$';
old_pwd = get_old_info(yppwd->newpw.pw_name, domain);
if (NULL == old_pwd) {
logmsg(MSG_NOTIMECHECK, LOG_ERR,
"Could not get old information for %s in "
"domain %s", yppwd->newpw.pw_name, domain);
return (ans);
}
ans = proc_request(yppwd, old_pwd, root_on_master, domain);
free_pwd_entry(old_pwd);
return (ans);
}
int
proc_request(struct yppasswd *yppwd, struct passwd_entry *old_pwd,
bool_t root_on_master, char *domain)
{
struct sigaction sa, osa1, osa2, osa3;
int ans;
if ((0 != strcmp(crypt(yppwd->oldpass, old_pwd->pw_passwd),
old_pwd->pw_passwd)) && !root_on_master) {
logmsg(MSG_NOTIMECHECK, LOG_NOTICE, "Passwd incorrect %s",
yppwd->newpw.pw_name);
return (7);
}
ans = modify_ent(yppwd, old_pwd, root_on_master, domain);
if (0 != ans)
return (ans);
old_pwd->pwd_str = create_pwd_str(old_pwd, FALSE);
if (NULL == old_pwd->pwd_str) {
logmsg(MSG_NOTIMECHECK, LOG_ERR,
"Could not create passwd entry");
return (2);
}
if (old_pwd->adjunct) {
old_pwd->adjunct_str = create_pwd_str(old_pwd, TRUE);
if (NULL == old_pwd->adjunct_str) {
logmsg(MSG_NOTIMECHECK, LOG_ERR,
"Could not create adjunct entry");
return (2);
}
} else {
old_pwd->adjunct_str = NULL;
}
ans = put_new_info(old_pwd, domain);
if (0 != ans) {
return (ans);
}
memset(&sa, 0, sizeof (struct sigaction));
sa.sa_handler = SIG_IGN;
sigaction(SIGTSTP, &sa, (struct sigaction *)0);
sigaction(SIGHUP, &sa, &osa1);
sigaction(SIGINT, &sa, &osa2);
sigaction(SIGQUIT, &sa, &osa3);
ans = proc_maps(domain, old_pwd);
sigaction(SIGHUP, &osa1, (struct sigaction *)0);
sigaction(SIGINT, &osa2, (struct sigaction *)0);
sigaction(SIGQUIT, &osa3, (struct sigaction *)0);
return (ans);
}
int
proc_maps(char *domain, struct passwd_entry *pwd)
{
char **map_list;
int ans = 0;
map_list = get_passwd_list(FALSE, domain);
if (map_list != NULL) {
ans = proc_map_list(map_list, domain, pwd, FALSE);
free_passwd_list(map_list);
if (0 != ans)
return (ans);
}
map_list = get_passwd_list(TRUE, domain);
if (map_list != NULL) {
ans = proc_map_list(map_list, domain, pwd, TRUE);
free_passwd_list(map_list);
}
return (ans);
}
int
proc_map_list(char **map_list, char *domain,
struct passwd_entry *pwd, bool_t adjunct_flag)
{
char *myself = "proc_map_list";
char *map_name;
char cmdbuf[BUFSIZ];
int map_name_len = 0;
int index, ans = 0;
if ((adjunct_flag) && (!pwd->adjunct)) {
logmsg(MSG_NOTIMECHECK, LOG_INFO,
"Have adjunct map list but no adjunct data in DIT");
return (0);
}
for (index = 0; map_list[index] != NULL; index ++)
if (map_name_len < strlen(map_list[index]))
map_name_len = strlen(map_list[index]);
map_name_len += strlen(YPDBPATH);
map_name_len += strlen(NTOL_PREFIX);
map_name_len += strlen(domain);
map_name_len += 3;
if (NULL == (map_name = am(myself, map_name_len))) {
logmsg(MSG_NOMEM, LOG_ERR, "Could not alloc map name");
return (2);
}
for (index = 0; map_list[index] != NULL; index ++) {
strcpy(map_name, YPDBPATH);
add_separator(map_name);
strcat(map_name, domain);
add_separator(map_name);
strcat(map_name, NTOL_PREFIX);
strcat(map_name, map_list[index]);
if (0 != (ans = update_single_map(map_name, pwd, adjunct_flag)))
break;
}
sfree(map_name);
if (mflag && (0 == ans)) {
for (index = 0; (map_name = map_list[index]) != NULL;
index ++) {
if (fork() == 0) {
strcpy(cmdbuf, "/usr/lib/netsvc/yp/yppush ");
strcat(cmdbuf, map_name);
if (0 > system(cmdbuf))
logmsg(MSG_NOTIMECHECK, LOG_ERR,
"Could not initiate yppush");
exit(0);
}
}
}
return (ans);
}
int
update_single_map(char *map_name, struct passwd_entry *pwd, bool_t adjunct_flag)
{
DBM *map;
int res;
datum data, key;
if (adjunct_flag)
data.dptr = pwd->adjunct_str;
else
data.dptr = pwd->pwd_str;
data.dsize = strlen(data.dptr);
key.dptr = NULL;
if (strend(map_name, BYNAME))
key.dptr = pwd->pw_name;
if (strend(map_name, BYUID))
key.dptr = pwd->pw_uid;
if (strend(map_name, BYGID))
key.dptr = pwd->pw_gid;
if (NULL == key.dptr) {
logmsg(MSG_NOTIMECHECK, LOG_ERR,
"Unrecognized map type %s", map_name);
return (0);
}
key.dsize = strlen(key.dptr);
map = shim_dbm_open(map_name, O_RDWR, 0600);
if (NULL == map) {
logmsg(MSG_NOTIMECHECK, LOG_ERR, "Could not open %s", map_name);
return (0);
}
if (SUCCESS != lock_map_update((map_ctrl *)map)) {
logmsg(MSG_NOTIMECHECK, LOG_ERR,
"Could not lock map %s for update", map_name);
shim_dbm_close(map);
return (2);
}
res = dbm_store(((map_ctrl *)map)->entries, key, data, DBM_REPLACE);
update_entry_ttl((map_ctrl *)map, &key, TTL_RAND);
if (FAILURE == update_timestamp(((map_ctrl *)map)->entries)) {
logmsg(MSG_NOTIMECHECK, LOG_ERR, "Could not update "
"YP_LAST_MODIFIED %s will not be pushed this time",
map_name);
}
unlock_map_update((map_ctrl *)map);
shim_dbm_close(map);
if (0 != res) {
logmsg(MSG_NOTIMECHECK, LOG_ERR,
"Could not update map %s", map_name);
return (2);
}
return (0);
}
bool_t
strend(char *s1, char *s2)
{
int len_dif;
len_dif = strlen(s1) - strlen(s2);
if (0 > len_dif)
return (FALSE);
if (0 == strcmp(s1 + len_dif, s2))
return (TRUE);
return (FALSE);
}
int
modify_ent(struct yppasswd *yppwd, struct passwd_entry *old_ent,
bool_t root_on_master, char *domain)
{
int change_list;
struct spwd *shadow;
time_t now;
change_list = get_change_list(yppwd, old_ent);
if (!change_list) {
logmsg(MSG_NOTIMECHECK, LOG_NOTICE,
"No change for %s", yppwd->newpw.pw_name);
return (3);
}
if ((change_list & CNG_SH) && (!validloginshell(old_ent->pw_shell,
yppwd->newpw.pw_shell, root_on_master)))
return (2);
if (change_list & CNG_PASSWD) {
shadow = get_old_shadow(yppwd->newpw.pw_name, domain);
if (NULL != shadow) {
now = DAY_NOW;
if (shadow->sp_max != -1) {
if (now < shadow->sp_lstchg + shadow->sp_min) {
logmsg(MSG_NOTIMECHECK, LOG_ERR,
"Sorry: < %ld days since "
"the last change", shadow->sp_min);
free_shadow_entry(shadow);
return (2);
}
}
shadow->sp_lstchg = now;
write_shadow_info(domain, shadow);
free_shadow_entry(shadow);
}
}
if (change_list & CNG_GECOS) {
if (NULL != old_ent->pw_gecos)
sfree(old_ent->pw_gecos);
old_ent->pw_gecos = strdup(yppwd->newpw.pw_gecos);
if (NULL == old_ent->pw_gecos) {
logmsg(MSG_NOMEM, LOG_ERR, "Could not allocate gecos");
return (2);
}
}
if (change_list & CNG_SH) {
if (NULL != old_ent->pw_shell)
sfree(old_ent->pw_shell);
old_ent->pw_shell = strdup(yppwd->newpw.pw_shell);
if (NULL == old_ent->pw_shell) {
logmsg(MSG_NOMEM, LOG_ERR, "Could not allocate shell");
return (2);
}
}
if (change_list & CNG_PASSWD) {
if (NULL != old_ent->pw_passwd)
sfree(old_ent->pw_passwd);
old_ent->pw_passwd = strdup(yppwd->newpw.pw_passwd);
if (NULL == old_ent->pw_passwd) {
logmsg(MSG_NOMEM, LOG_ERR, "Could not allocate passwd");
return (2);
}
}
return (0);
}
int
get_change_list(struct yppasswd *yppwd, struct passwd_entry *old_ent)
{
int list = 0;
char *p;
p = yppwd->newpw.pw_passwd;
if ((!nopw) &&
p && *p &&
!(*p++ == '#' && *p++ == '#' &&
(strcmp(p, old_ent->pw_name) == 0)) &&
(strcmp(crypt(old_ent->pw_passwd,
yppwd->newpw.pw_passwd), yppwd->newpw.pw_passwd) != 0))
list |= CNG_PASSWD;
if ((NULL != old_ent->pw_shell) &&
(!noshell) &&
(strcmp(old_ent->pw_shell, yppwd->newpw.pw_shell) != 0)) {
if (single)
list = 0;
list |= CNG_SH;
}
if ((NULL != old_ent->pw_gecos) &&
(!nogecos) &&
(strcmp(old_ent->pw_gecos, yppwd->newpw.pw_gecos) != 0)) {
if (single)
list = 0;
list |= CNG_GECOS;
}
return (list);
}
suc_code
decode_pwd_entry(datum *data, struct passwd_entry *pwd, bool_t adjunct)
{
char *myself = "decode_pwd_entry";
char *p, *str_end, *temp;
str_end = data->dptr + data->dsize;
if (NULL == (p = get_next_token(data->dptr, &temp, str_end)))
return (FAILURE);
if (adjunct) {
if (NULL != pwd->pw_name)
sfree(pwd->pw_name);
}
pwd->pw_name = temp;
if (NULL == (p = get_next_token(p, &temp, str_end)))
return (FAILURE);
if (adjunct) {
if (NULL != pwd->pw_passwd)
sfree(pwd->pw_passwd);
}
pwd->pw_passwd = temp;
if (adjunct) {
pwd->adjunct_tail = am(myself, str_end - p + 1);
if (NULL == pwd->adjunct_tail)
return (FAILURE);
strncpy(pwd->adjunct_tail, p, str_end - p);
pwd->adjunct_tail[str_end - p] = '\0';
pwd->adjunct = TRUE;
return (SUCCESS);
}
if (NULL == (p = get_next_token(p, &(pwd->pw_uid), str_end)))
return (FAILURE);
if (NULL == (p = get_next_token(p, &(pwd->pw_gid), str_end)))
return (FAILURE);
if (NULL == (p = get_next_token(p, &(pwd->pw_gecos), str_end)))
return (FAILURE);
if (NULL == (p = get_next_token(p, &(pwd->pw_dir), str_end)))
return (FAILURE);
get_next_token(p, &(pwd->pw_shell), str_end);
if (NULL == pwd->pw_shell)
return (FAILURE);
return (SUCCESS);
}
static char *
get_next_token(char *str, char **op, char *str_end)
{
char *myself = "get_next_token";
char *p, *tok_start, *tok_end;
p = str;
while (' ' == *p)
p++;
tok_start = p;
tok_end = p;
while ((str_end + 1 != p) && (COLON_CHAR != *p)) {
if (' ' != *p)
tok_end = p;
p++;
}
if (NULL != op) {
*op = am(myself, tok_end - tok_start + 2);
if (NULL == *op) {
logmsg(MSG_NOMEM, LOG_ERR,
"Could not alloc memory for token");
return (NULL);
}
strncpy(*op, tok_start, tok_end - tok_start + 1);
(*op)[tok_end - tok_start + 1] = '\0';
}
if ('\0' == *p)
return (NULL);
p++;
return (p);
}
void
free_pwd_entry(struct passwd_entry *pwd)
{
if (NULL != pwd->pw_name)
sfree(pwd->pw_name);
if (NULL != pwd->pw_passwd)
sfree(pwd->pw_passwd);
if (NULL != pwd->pw_gecos)
sfree(pwd->pw_gecos);
if (NULL != pwd->pw_shell)
sfree(pwd->pw_shell);
if (NULL != pwd->pw_dir)
sfree(pwd->pw_dir);
if (NULL != pwd->adjunct_tail)
sfree(pwd->adjunct_tail);
if (NULL != pwd->pwd_str)
sfree(pwd->pwd_str);
if (NULL != pwd->adjunct_str)
sfree(pwd->adjunct_str);
sfree(pwd);
}
char *
create_pwd_str(struct passwd_entry *pwd, bool_t adjunct)
{
char *myself = "create_pwd_str";
char *s;
int len;
char sep_str[2] = {COLON_CHAR, '\0'};
len = strlen(pwd->pw_name) + 1;
len += strlen(pwd->pw_passwd) + 1;
if (adjunct) {
len += strlen(pwd->adjunct_tail) + 1;
} else {
len += strlen(pwd->pw_uid) + 1;
len += strlen(pwd->pw_gid) + 1;
len += strlen(pwd->pw_gecos) + 1;
len += strlen(pwd->pw_dir) + 1;
len += strlen(pwd->pw_shell) + 1;
}
s = am(myself, len);
if (NULL == s)
return (NULL);
strcpy(s, pwd->pw_name);
strcat(s, sep_str);
if (!adjunct) {
if (pwd->adjunct) {
strcat(s, "##");
strcat(s, pwd->pw_name);
} else {
strcat(s, pwd->pw_passwd);
}
strcat(s, sep_str);
strcat(s, pwd->pw_uid);
strcat(s, sep_str);
strcat(s, pwd->pw_gid);
strcat(s, sep_str);
strcat(s, pwd->pw_gecos);
strcat(s, sep_str);
strcat(s, pwd->pw_dir);
strcat(s, sep_str);
strcat(s, pwd->pw_shell);
} else {
strcat(s, pwd->pw_passwd);
strcat(s, sep_str);
strcat(s, pwd->adjunct_tail);
}
return (s);
}
struct passwd_entry *
get_old_info(char *name, char *domain)
{
char *myself = "get_old_info";
struct passwd_entry *old_passwd;
datum key, data;
suc_code res;
key.dptr = name;
key.dsize = strlen(key.dptr);
read_from_dit(PASSWD_MAPPING, domain, &key, &data);
if (NULL == data.dptr) {
logmsg(MSG_NOTIMECHECK, LOG_ERR,
"Could not read old pwd for %s", name);
return (NULL);
}
old_passwd = am(myself, sizeof (struct passwd_entry));
if (NULL == old_passwd) {
logmsg(MSG_NOMEM, LOG_ERR, "Could not alloc for pwd decode");
sfree(data.dptr);
return (NULL);
}
old_passwd->pw_name = NULL;
old_passwd->pw_passwd = NULL;
old_passwd->pw_uid = NULL;
old_passwd->pw_gid = NULL;
old_passwd->pw_gecos = NULL;
old_passwd->pw_dir = NULL;
old_passwd->pw_shell = NULL;
old_passwd->adjunct_tail = NULL;
old_passwd->pwd_str = NULL;
old_passwd->adjunct_str = NULL;
old_passwd->adjunct = FALSE;
res = decode_pwd_entry(&data, old_passwd, FALSE);
sfree(data.dptr);
if (SUCCESS != res) {
free_pwd_entry(old_passwd);
return (NULL);
}
read_from_dit(PASSWD_ADJUNCT_MAPPING, domain, &key, &data);
if (NULL == data.dptr) {
old_passwd->adjunct = FALSE;
} else {
res = decode_pwd_entry(&data, old_passwd, TRUE);
sfree(data.dptr);
if (SUCCESS != res) {
free_pwd_entry(old_passwd);
return (NULL);
}
}
return (old_passwd);
}
int
put_new_info(struct passwd_entry *pwd, char *domain)
{
datum key, data;
data.dptr = pwd->pwd_str;
data.dsize = strlen(data.dptr);
key.dptr = pwd->pw_name;
key.dsize = strlen(key.dptr);
if (SUCCESS != write_to_dit(PASSWD_MAPPING, domain, key, data,
TRUE, FALSE))
return (2);
if (pwd->adjunct) {
data.dptr = pwd->adjunct_str;
data.dsize = strlen(data.dptr);
key.dptr = pwd->pw_name;
key.dsize = strlen(key.dptr);
if (SUCCESS != write_to_dit(PASSWD_ADJUNCT_MAPPING, domain,
key, data, TRUE, FALSE))
return (2);
}
return (0);
}
struct spwd *
get_old_shadow(char *name, char *domain)
{
char *myself = "get_old_shadow";
struct spwd *sp;
datum key, data;
suc_code res;
key.dptr = name;
key.dsize = strlen(key.dptr);
read_from_dit(AGEING_MAPPING, domain, &key, &data);
if (NULL == data.dptr) {
return (NULL);
}
if (NULL == (sp = am(myself, sizeof (struct spwd)))) {
logmsg(MSG_NOMEM, LOG_ERR,
"Could not alloc for shadow decode");
sfree(data.dptr);
return (NULL);
}
sp->sp_namp = NULL;
sp->sp_pwdp = NULL;
res = decode_shadow_entry(&data, sp);
sfree(data.dptr);
if (SUCCESS != res) {
free_shadow_entry(sp);
return (NULL);
}
return (sp);
}
suc_code
decode_shadow_entry(datum *data, struct spwd *sp)
{
char *p, *str_end, *temp;
str_end = data->dptr + data->dsize;
if (NULL == (p = get_next_token(data->dptr, &(sp->sp_namp), str_end)))
return (FAILURE);
if (NULL == (p = get_next_token(p, &temp, str_end)))
return (FAILURE);
sp->sp_lstchg = atoi(temp);
if (NULL == (p = get_next_token(p, &temp, str_end)))
return (FAILURE);
sp->sp_min = atoi(temp);
if (NULL == (p = get_next_token(p, &temp, str_end)))
return (FAILURE);
sp->sp_max = atoi(temp);
if (NULL == (p = get_next_token(p, &temp, str_end)))
return (FAILURE);
sp->sp_warn = atoi(temp);
if (NULL == (p = get_next_token(p, &temp, str_end)))
return (FAILURE);
sp->sp_inact = atoi(temp);
if (NULL == (p = get_next_token(p, &temp, str_end)))
return (FAILURE);
sp->sp_expire = atoi(temp);
if (NULL != (p = get_next_token(p, &temp, str_end)))
return (FAILURE);
sp->sp_flag = atoi(temp);
return (SUCCESS);
}
suc_code
write_shadow_info(char *domain, struct spwd *sp)
{
char *myself = "write_shadow_info";
datum key, data;
char *str;
suc_code res;
int len;
len = strlen(sp->sp_namp) + 1;
len += 7 * (3 * sizeof (long) + 1);
str = am(myself, len);
if (NULL == str) {
logmsg(MSG_NOMEM, LOG_ERR, "Could not aloc for shadow write");
return (FAILURE);
}
sprintf(str, "%s%c%d%c%d%c%d%c%d%c%d%c%d%c%d",
sp->sp_namp, COLON_CHAR,
sp->sp_lstchg, COLON_CHAR,
sp->sp_min, COLON_CHAR,
sp->sp_max, COLON_CHAR,
sp->sp_warn, COLON_CHAR,
sp->sp_inact, COLON_CHAR,
sp->sp_expire, COLON_CHAR,
sp->sp_flag);
data.dptr = str;
data.dsize = strlen(data.dptr);
key.dptr = sp->sp_namp;
key.dsize = strlen(key.dptr);
res = write_to_dit(AGEING_MAPPING, domain, key, data, TRUE, FALSE);
sfree(str);
return (res);
}
void
free_shadow_entry(struct spwd *spwd)
{
if (NULL != spwd->sp_namp)
sfree(spwd->sp_namp);
if (NULL != spwd->sp_pwdp)
sfree(spwd->sp_pwdp);
sfree(spwd);
}