summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgww <none@none>2005-08-29 14:56:04 -0700
committergww <none@none>2005-08-29 14:56:04 -0700
commitb816ddf83939c2b433da956720fad32dfb172096 (patch)
tree1d250d1dcaf3177fc65e6b82f2f59ebec5e5dfe9
parentfa626f0c30d0a6dcbc5bb89c70534722f6380329 (diff)
downloadillumos-joyent-b816ddf83939c2b433da956720fad32dfb172096.tar.gz
PSARC/2005/293 passwd -s Stable parsable output
PSARC/2005/492 logins -x password field sync up 5003383 logins(1M) is inconsistent on what makes an account locked. 6294509 logins(1M) -l is pig dog slow 6296008 passwd -s is incomplete: implement PSARC/2005/293 passwd -s Stable parsable output
-rw-r--r--usr/src/cmd/logins/logins.c467
-rw-r--r--usr/src/cmd/passwd/passwd.c5
2 files changed, 139 insertions, 333 deletions
diff --git a/usr/src/cmd/logins/logins.c b/usr/src/cmd/logins/logins.c
index e911ecbe07..a095213b10 100644
--- a/usr/src/cmd/logins/logins.c
+++ b/usr/src/cmd/logins/logins.c
@@ -111,7 +111,6 @@
struct reqgrp {
char *groupname; /* Requested group name */
struct reqgrp *next; /* Next item in the list */
- int found; /* TRUE if group in /etc/group */
gid_t groupID; /* Group's ID */
};
@@ -248,132 +247,11 @@ wrtmsg(int severity, char *action, char *tag, char *text, ...)
}
}
-
-/*
- * These functions allocate space for the information we gather.
- * It works by having a memory heap with strings allocated from
- * the end of the heap and structures (aligned data) allocated
- * from the beginning of the heap. It begins with a 4k block of
- * memory then allocates memory in 4k chunks. These functions
- * should never fail. If they do, they report the problem and
- * exit with an exit code of 101.
- *
- * Functions contained:
- * allocblk Allocates a block of memory, aligned on a
- * 4-byte (double-word) boundary.
- * allocstr Allocates a block of memory with no
- * particular alignment
- *
- * Constant definitions:
- * ALLOCBLKSZ Size of a chunk of main memory allocated
- * using malloc()
- *
- * Static data:
- * nextblkaddr Address of the next available chunk of
- * aligned space in the heap
- * laststraddr Address of the last chunk of unaligned space
- * allocated from the heap
- * toomuchspace Message to write if someone attempts to allocate
- * too much space (>ALLOCBLKSZ bytes)
- * memallocdif Message to write if there is a problem
- * allocating main menory.
- */
-
-#define ALLOCBLKSZ 4096
-
-static char *nextblkaddr = NULL;
-static char *laststraddr = NULL;
-#define MEMALLOCDIF "Memory allocation difficulty. Command terminates"
-#define TOOMUCHSPACE "Internal space allocation error. Command terminates"
-
-
-/*
- * void *allocblk(size)
- * unsigned int size
- *
- * This function allocates a block of aligned (4-byte or
- * double-word boundary) memory from the program's heap.
- * It returns a pointer to that block of allocated memory.
- *
- * Arguments:
- * size Minimum number of bytes to allocate (will
- * round up to multiple of 4)
- *
- * Returns: void *
- * Pointer to the allocated block of memory
- */
-
-static void *
-allocblk(unsigned int size)
-{
- char *rtnval;
-
- /* Make sure the sizes are aligned correctly */
- if ((size = size + (4 - (size % 4))) > ALLOCBLKSZ) {
- wrtmsg(MM_ERROR, MM_NULLACT, MM_NULLTAG, gettext(TOOMUCHSPACE));
- exit(101);
- }
-
- /* Set up the value we're going to return */
- rtnval = nextblkaddr;
-
- /* Get the space we need off of the heap */
- if ((nextblkaddr += size) >= laststraddr) {
- if (!(rtnval = (char *)malloc(ALLOCBLKSZ))) {
- wrtmsg(MM_ERROR, MM_NULLACT, MM_NULLTAG,
- gettext(MEMALLOCDIF));
- exit(101);
- }
- laststraddr = rtnval + ALLOCBLKSZ;
- nextblkaddr = rtnval + size;
- }
-
- /* We're through */
- return ((void *)rtnval);
-}
-
-
-/*
- * char *allocstr(nbytes)
- * unsigned int nbytes
- *
- * This function allocates a block of unaligned memory from the
- * program's heap. It returns a pointer to that block of allocated
- * memory.
- *
- * Arguments:
- * nbytes Number of bytes to allocate
- *
- * Returns: char *
- * Pointer to the allocated block of memory
- */
-
-static char *
-allocstr(unsigned int nchars)
-{
- if (nchars > ALLOCBLKSZ) {
- wrtmsg(MM_ERROR, MM_NULLACT, MM_NULLTAG, gettext(TOOMUCHSPACE));
- exit(101);
- }
- if (laststraddr == NULL ||
- (laststraddr -= nchars) < nextblkaddr) {
- if (!(nextblkaddr = (char *)malloc(ALLOCBLKSZ))) {
- wrtmsg(MM_ERROR, MM_NULLACT, MM_NULLTAG,
- gettext(MEMALLOCDIF));
- exit(101);
- }
- laststraddr = nextblkaddr + ALLOCBLKSZ - nchars;
- }
- return (laststraddr);
-}
-
-
/*
* These functions control the group membership list, as found in
* the /etc/group file.
*
* Functions included:
- * initmembers Initialize the membership list (to NULL)
* addmember Adds a member to the membership list
* isamember Looks for a particular login-ID in the
* list of members
@@ -393,25 +271,6 @@ struct grpmember {
static struct grpmember *membershead;
-
-/*
- * void initmembers()
- *
- * This function initializes the list of members of specified groups.
- *
- * Arguments: None
- *
- * Returns: Void
- */
-
-static void
-initmembers(void)
-{
- /* Set up the members list to be a null member's list */
- membershead = NULL;
-}
-
-
/*
* void addmember(p)
* char *p
@@ -432,8 +291,8 @@ addmember(char *p)
{
struct grpmember *new; /* Member being added */
- new = (struct grpmember *)allocblk(sizeof (struct grpmember));
- new->membername = strcpy(allocstr((unsigned int)strlen(p)+1), p);
+ new = malloc(sizeof (struct grpmember));
+ new->membername = strdup(p);
new->next = membershead;
membershead = new;
}
@@ -536,7 +395,7 @@ static struct display *displayhead;
static void
initdisp(void)
{
- displayhead = (struct display *)allocblk(sizeof (struct display));
+ displayhead = malloc(sizeof (struct display));
displayhead->nextlogin = NULL;
displayhead->nextuid = NULL;
displayhead->loginID = "";
@@ -588,27 +447,19 @@ adddisp(struct passwd *pwent)
}
/* Insert this value in the list, only if it is unique though */
if (compare != 0) {
- new = (struct display *)allocblk(sizeof (struct display));
- new->loginID = strcpy(allocstr(
- (unsigned int)strlen(pwent->pw_name)+1), pwent->pw_name);
+ new = malloc(sizeof (struct display));
+ new->loginID = strdup(pwent->pw_name);
if (pwent->pw_comment && pwent->pw_comment[0] != '\0') {
- new->freefield = strcpy(allocstr(
- (unsigned int)strlen(pwent->pw_comment)+1),
- pwent->pw_comment);
+ new->freefield = strdup(pwent->pw_comment);
} else {
- new->freefield = strcpy(allocstr(
- (unsigned int)strlen(pwent->pw_gecos)+1),
- pwent->pw_gecos);
+ new->freefield = strdup(pwent->pw_gecos);
}
if (!pwent->pw_shell || !(*pwent->pw_shell)) {
new->shell = "/sbin/sh";
} else {
- new->shell = strcpy(allocstr(
- (unsigned int)strlen(pwent->pw_shell)+1),
- pwent->pw_shell);
+ new->shell = strdup(pwent->pw_shell);
}
- new->iwd = strcpy(allocstr(
- (unsigned int)strlen(pwent->pw_dir)+1), pwent->pw_dir);
+ new->iwd = strdup(pwent->pw_dir);
new->userID = pwent->pw_uid;
new->groupID = pwent->pw_gid;
new->secgrplist = NULL;
@@ -714,6 +565,15 @@ applygroup(int allgroups)
struct secgrp *psecgrp; /* Block allocated for this info */
struct secgrp *psrch; /* Secondary group -- for searching */
+ if (!allgroups) {
+ /* short circute getting all the groups */
+ for (dp = displayhead->nextuid; dp; dp = dp->nextuid) {
+ if ((grent = getgrgid(dp->groupID)) != NULL) {
+ dp->groupname = strdup(grent->gr_name);
+ }
+ }
+ return;
+ }
/* For each group-ID in the /etc/group file ... */
while (grent = getgrent()) {
@@ -727,17 +587,12 @@ applygroup(int allgroups)
for (dp = displayhead->nextuid; dp; dp = dp->nextuid) {
if ((dp->groupID == grent->gr_gid) && !dp->groupname) {
if (!p) {
- p = strcpy(allocstr(
- (unsigned int)strlen(
- grent->gr_name)+1), grent->gr_name);
+ p = strdup(grent->gr_name);
}
dp->groupname = p;
}
}
- if (!allgroups) {
- continue;
- }
/*
* If we're to be displaying secondary group membership,
* leaf through the list of group members. Then, attempt
@@ -753,12 +608,9 @@ applygroup(int allgroups)
*pp)) == 0) &&
!(grent->gr_gid == dp->groupID)) {
if (!p) {
- p = strcpy(allocstr(
- (unsigned int)strlen(
- grent->gr_name)+1),
- grent->gr_name);
+ p = strdup(grent->gr_name);
}
- psecgrp = (struct secgrp *)allocblk(
+ psecgrp = malloc(
sizeof (struct secgrp));
psecgrp->groupID = grent->gr_gid;
psecgrp->groupname = p;
@@ -806,7 +658,6 @@ applypasswd(void)
struct display *dp; /* Ptr to current element */
struct spwd *psp; /* Pointer to a shadow-file entry */
struct tm *ptm; /* Pointer to a time-of-day structure */
- char *p; /* Running character pointer */
time_t pwchg; /* System-time of last pwd chg */
time_t pwexp; /* System-time of password expiration */
@@ -822,7 +673,7 @@ applypasswd(void)
for (dp = displayhead->nextuid; dp; dp = dp->nextuid) {
/* Allocate structure space for the password description */
- ppasswd = (struct pwdinfo *)allocblk(sizeof (struct pwdinfo));
+ ppasswd = malloc(sizeof (struct pwdinfo));
dp->passwdinfo = ppasswd;
/*
@@ -830,7 +681,7 @@ applypasswd(void)
* that the login is locked
*/
- if (!(psp = getspnam(dp->loginID))) {
+ if ((psp = getspnam(dp->loginID)) == NULL) {
pwchg = 0L; /* Epoch */
ppasswd->passwdstatus = "LK"; /* LK, Locked */
ppasswd->mindaystilchg = 0L;
@@ -841,33 +692,22 @@ applypasswd(void)
} else {
/*
* Otherwise, fill in the password information from the
- * info in the shadow file entry
+ * info in the shadow entry
*/
- /* See if the login has no password */
- if (!psp->sp_pwdp || !(*psp->sp_pwdp)) {
+ if (psp->sp_pwdp == NULL || (*psp->sp_pwdp) == '\0')
ppasswd->passwdstatus = "NP";
- } else if (strlen(psp->sp_pwdp) != 13) {
- /*
- * See if the login is explicitly locked
- * (encrypted password is <13 characters)
- */
+ else if (strncmp(psp->sp_pwdp, LOCKSTRING,
+ sizeof (LOCKSTRING)-1) == 0)
ppasswd->passwdstatus = "LK";
- } else {
- /*
- * If it's a valid encrypted password,
- * the login is password protected
- */
+ else if (strncmp(psp->sp_pwdp, NOLOGINSTRING,
+ sizeof (NOLOGINSTRING)-1) == 0)
+ ppasswd->passwdstatus = "NL";
+ else if ((strlen(psp->sp_pwdp) == 13 &&
+ psp->sp_pwdp[0] != '$') ||
+ psp->sp_pwdp[0] == '$')
ppasswd->passwdstatus = "PS";
- for (p = psp->sp_pwdp; *p; p++) {
- if (!isalnum(*p) &&
- (*p != '.') &&
- (*p != '/')) {
- ppasswd->passwdstatus = "LK";
- break;
- }
- }
- }
-
+ else
+ ppasswd->passwdstatus = "UN";
/*
* Set up the last-changed date,
* the minimum days between changes,
@@ -1251,16 +1091,6 @@ genlogreport(int pipeflag, int xtndflag, int expflag)
}
}
-
-char *
-strcpmalloc(char *str)
-{
- if (str == NULL)
- return (NULL);
-
- return (strcpy(allocstr((unsigned int)strlen(str)+1), str));
-}
-
struct localpw {
struct localpw *next;
struct passwd pw;
@@ -1273,45 +1103,68 @@ struct localpw *pwptr;
int in_localgetpwent = 0; /* Set if in local_getpwent */
+static struct localpw *
+fill_localpw(struct localpw *lpw, struct passwd *pw) {
+ struct localpw *cur;
+
+ /*
+ * Copy the data -- we have to alloc areas for it all
+ */
+ lpw->pw.pw_name = strdup(pw->pw_name);
+ lpw->pw.pw_passwd = strdup(pw->pw_passwd);
+ lpw->pw.pw_uid = pw->pw_uid;
+ lpw->pw.pw_gid = pw->pw_gid;
+ lpw->pw.pw_age = strdup(pw->pw_age);
+ lpw->pw.pw_comment = strdup(pw->pw_comment);
+ lpw->pw.pw_gecos = strdup(pw->pw_gecos);
+ lpw->pw.pw_dir = strdup(pw->pw_dir);
+ lpw->pw.pw_shell = strdup(pw->pw_shell);
+
+ cur = lpw;
+ lpw->next = malloc(sizeof (struct localpw));
+ return (cur);
+}
+
void
-build_localpw(void)
+build_localpw(struct reqlogin *req_head)
{
struct localpw *next, *cur;
struct passwd *pw;
+ struct reqlogin *req_next;
- next = (struct localpw *)allocblk(sizeof (struct localpw));
+ next = malloc(sizeof (struct localpw));
pwtable = next;
- while ((pw = getpwent()) != NULL) {
- /*
- * Copy the data -- we have to alloc areas for it all
- */
- next->pw.pw_name = strcpmalloc(pw->pw_name);
- next->pw.pw_passwd = strcpmalloc(pw->pw_passwd);
- next->pw.pw_uid = pw->pw_uid;
- next->pw.pw_gid = pw->pw_gid;
- next->pw.pw_age = strcpmalloc(pw->pw_age);
- next->pw.pw_comment = strcpmalloc(pw->pw_comment);
- next->pw.pw_gecos = strcpmalloc(pw->pw_gecos);
- next->pw.pw_dir = strcpmalloc(pw->pw_dir);
- next->pw.pw_shell = strcpmalloc(pw->pw_shell);
-
- next->next = (struct localpw *)allocblk(
- sizeof (struct localpw));
-
- cur = next;
- next = next->next;
+ req_next = req_head;
+
+ while (req_next != NULL) {
+ if ((pw = getpwnam(req_next->loginname)) != NULL) {
+ /*
+ * Copy the data -- we have to alloc areas for it all
+ */
+ cur = fill_localpw(next, pw);
+ req_next->found = TRUE;
+ next = cur->next;
+ }
+
+ req_next = req_next->next;
}
- /*
- * At this point we have one extra (struct localpw) allocated;
- * sine alloclbk doesn't have a freeblk, we just leave it unreferenced.
- */
+ if (req_head == NULL) {
+ while ((pw = getpwent()) != NULL) {
+ /*
+ * Copy the data -- we have to alloc areas for it all
+ */
+ cur = fill_localpw(next, pw);
+ next = cur->next;
+ }
+ }
if (pwtable == next) {
pwtable = NULL;
} else {
+ free(next);
cur->next = NULL;
}
@@ -1605,21 +1458,51 @@ main(int argc, char *argv[])
exit(1);
}
-
-
/*
* The following section does preparation work, setting up for
* building the list of logins to display
*/
+
/*
- * Very first thing, build an in-core structure of passwd file entries.
- * This is important since we have to assume that getpwent() is going
- * out to one or more network name services that could be changing
- * on the fly. This will limit us to one pass through the network data.
+ * If -l logins is on the command line, build a list of
+ * logins we're to generate reports for.
*/
- build_localpw();
+ if (l_seen) {
+ reqloginhead = NULL;
+ if (token = strtok(l_arg, ",")) {
+ plogin = malloc(sizeof (struct reqlogin));
+ plogin->loginname = token;
+ plogin->found = FALSE;
+ plogin->next = NULL;
+ reqloginhead = plogin;
+ qlogin = plogin;
+ while (token = strtok(NULL, ",")) {
+ plogin = malloc(sizeof (struct reqlogin));
+ plogin->loginname = token;
+ plogin->found = FALSE;
+ plogin->next = NULL;
+ qlogin->next = plogin;
+ qlogin = plogin;
+ }
+ }
+ /*
+ * Build an in-core structure of just the passwd database
+ * entries requested. This greatly reduces the time
+ * to get all entries and filter later.
+ */
+ build_localpw(reqloginhead);
+ } else {
+ /*
+ * Build an in-core structure of all passwd database
+ * entries. This is important since we have to assume that
+ * getpwent() is going out to one or more network name
+ * services that could be changing on the fly. This will
+ * limit us to one pass through the network data.
+ */
+ build_localpw(NULL);
+ }
/*
* If the -g groups option was on the command line, build a
@@ -1630,19 +1513,15 @@ main(int argc, char *argv[])
groupcount = 0;
reqgrphead = NULL;
if (token = strtok(g_arg, ",")) {
- pgrp = (struct reqgrp *)allocblk(
- sizeof (struct reqgrp));
+ pgrp = malloc(sizeof (struct reqgrp));
pgrp->groupname = token;
- pgrp->found = FALSE;
pgrp->next = NULL;
groupcount++;
reqgrphead = pgrp;
qgrp = pgrp;
while (token = strtok(NULL, ",")) {
- pgrp = (struct reqgrp *)allocblk(
- sizeof (struct reqgrp));
+ pgrp = malloc(sizeof (struct reqgrp));
pgrp->groupname = token;
- pgrp->found = FALSE;
pgrp->next = NULL;
groupcount++;
qgrp->next = pgrp;
@@ -1653,50 +1532,11 @@ main(int argc, char *argv[])
/*
- * If -l logins is on the command line, build a list of
- * logins we're to generate reports for.
- */
-
- if (l_seen) {
- reqloginhead = NULL;
- if (token = strtok(l_arg, ",")) {
- plogin = (struct reqlogin *)allocblk(
- sizeof (struct reqlogin));
- plogin->loginname = token;
- plogin->found = FALSE;
- plogin->next = NULL;
- reqloginhead = plogin;
- qlogin = plogin;
- while (token = strtok(NULL, ",")) {
- plogin = (struct reqlogin *)allocblk(
- sizeof (struct reqlogin));
- plogin->loginname = token;
- plogin->found = FALSE;
- plogin->next = NULL;
- qlogin->next = plogin;
- qlogin = plogin;
- }
- }
- while (pwent = local_getpwent()) {
- done = FALSE;
- for (plogin = reqloginhead; !done && plogin;
- plogin = plogin->next) {
- if (strcmp(pwent->pw_name,
- plogin->loginname) == 0) {
- plogin->found = TRUE;
- done = TRUE;
- }
- }
- }
- local_endpwent();
- }
-
- /*
* Generate the list of login information to display
*/
/* Initialize the login list */
- initmembers();
+ membershead = NULL;
/*
@@ -1705,62 +1545,25 @@ main(int argc, char *argv[])
*/
if (g_seen) {
+ /* For each group mentioned with the -g option ... */
+ for (pgrp = reqgrphead; (groupcount > 0) && pgrp;
+ pgrp = pgrp->next) {
+ if ((grent = getgrnam(pgrp->groupname)) != NULL) {
+ /*
+ * Remembering the group-ID for later
+ */
- /* For each group in the /etc/group file ... */
- while (grent = getgrent()) {
-
- /* For each group mentioned with the -g option ... */
- for (pgrp = reqgrphead; (groupcount > 0) && pgrp;
- pgrp = pgrp->next) {
-
- if (!pgrp->found) {
-
- /*
- * If the mentioned group is found
- * in the /etc/group file ...
- */
- if (strcmp(grent->gr_name,
- pgrp->groupname) == 0) {
-
- /*
- * Mark the entry is found,
- * remembering the group-ID
- * for later
- */
-
- pgrp->found = TRUE;
- groupcount--;
- pgrp->groupID = grent->gr_gid;
- for (pp = grent->gr_mem; *pp;
- pp++) {
- addmember(*pp);
- }
- }
+ groupcount--;
+ pgrp->groupID = grent->gr_gid;
+ for (pp = grent->gr_mem; *pp; pp++) {
+ addmember(*pp);
}
- }
- }
-
- /*
- * If any groups weren't found, write a message indicating
- * such, then continue
- */
-
- qgrp = NULL;
- for (pgrp = reqgrphead; pgrp; pgrp = pgrp->next) {
- if (!pgrp->found) {
+ } else {
wrtmsg(MM_WARNING, MM_NULLACT, MM_NULLTAG,
gettext("%s was not found"),
pgrp->groupname);
- if (!qgrp) {
- reqgrphead = pgrp->next;
- } else {
- qgrp->next = pgrp->next;
- }
- } else {
- qgrp = pgrp;
}
}
- endgrent();
}
diff --git a/usr/src/cmd/passwd/passwd.c b/usr/src/cmd/passwd/passwd.c
index 53ecf62c74..7b96606534 100644
--- a/usr/src/cmd/passwd/passwd.c
+++ b/usr/src/cmd/passwd/passwd.c
@@ -1289,8 +1289,11 @@ display_attr(char *usrname, attrlist *attributes)
else if (strncmp(passwd, NOLOGINSTRING,
sizeof (NOLOGINSTRING)-1) == 0)
status = "NL ";
- else
+ else if ((strlen(passwd) == 13 && passwd[0] != '$') ||
+ passwd[0] == '$')
status = "PS ";
+ else
+ status = "UN ";
break;
case ATTR_LSTCHG:
lstchg = attributes->data.val_i * DAY;