/*
Copyright (C) 2001-2006 Ben Kibbey <bjk@luxsci.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
#include <errno.h>
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "passwd.h"
#ifndef HAVE_STRSEP
#include "../strsep.c"
#endif
#ifndef HAVE_ERR_H
#include "../err.c"
#endif
void ui_module_init(int *chainable)
{
#ifdef DEBUG
fprintf(stderr, "%s: ui_module_init()\n", __FILE__);
#endif
/*
* Keep the password file open if possible (*BSD).
*/
#ifdef HAVE_SETPASSENT
setpassent(1);
#endif
if (getuid() == 0)
amroot = 1;
*chainable = 0;
return;
}
void ui_module_exit()
{
#ifdef DEBUG
fprintf(stderr, "%s: ui_module_exit()\n", __FILE__);
#endif
#ifdef HAVE_GETSPNAM
if (amroot)
endspent();
#endif
endpwent();
endgrent();
return;
}
/* See if the gecos options are valid. */
static int parse_gecos_options(const char *args)
{
int i = 0;
for (i = 0; i < strlen(args); i++) {
switch (args[i]) {
case 'n':
case '1':
case '2':
case '3':
case 'a':
break;
default:
return 1;
}
}
return 0;
}
/* Break up the gecos string into sections and add the sections to the output
* string array if needed. */
static void gecos_strings(char *str)
{
int i = 0;
char *buf;
const char *name, *first, *second, *third;
name = first = second = third = "-";
while ((buf = strsep(&str, ",")) != NULL) {
if (!buf[0])
continue;
switch (i++) {
case 0:
name = buf;
break;
case 1:
first = buf;
break;
case 2:
second = buf;
break;
case 3:
third = buf;
break;
default:
break;
}
}
for (i = 0; i < strlen(gecos_options); i++) {
switch (gecos_options[i]) {
case 'n':
add_string(&strings, name);
break;
case '1':
add_string(&strings, first);
break;
case '2':
add_string(&strings, second);
break;
case '3':
add_string(&strings, third);
break;
case 'a':
add_string(&strings, name);
add_string(&strings, first);
add_string(&strings, second);
add_string(&strings, third);
break;
default:
break;
}
}
return;
}
/* Get all groups that a user is a member of. The primary group will be the
* first added. */
static void groups(const struct passwd *pw, const int multi,
const int verbose)
{
struct group *grp;
char tmp[255];
char line[LINE_MAX];
gid_t primary = -1;
line[0] = '\0';
if ((grp = getgrgid(pw->pw_gid)) == NULL) {
snprintf(tmp, sizeof(tmp), "%li%s%s%s", (long) pw->pw_gid,
(verbose) ? "(" : "", (verbose) ? "!" : "",
(verbose) ? ")" : "");
add_string(&strings, tmp);
return;
}
primary = grp->gr_gid;
snprintf(tmp, sizeof(tmp), "%li%s%s%s%c", (long) pw->pw_gid,
(verbose) ? "(" : "", (verbose) ? grp->gr_name : "",
(verbose) ? ")" : "", multi);
strncat(line, tmp, sizeof(line));
#ifdef HAVE_SETGROUPENT
setgroupent(1);
#else
setgrent();
#endif
while ((grp = getgrent()) != NULL) {
char **members = grp->gr_mem;
while (*members) {
if (strcmp(*members++, pw->pw_name) == 0) {
if (grp->gr_gid == primary)
continue;
snprintf(tmp, sizeof(tmp), "%li%s%s%s%c", (long) grp->gr_gid,
(verbose) ? "(" : "", (verbose) ? grp->gr_name : "",
(verbose) ? ")" : "", multi);
strncat(line, tmp, sizeof(line));
}
}
}
/*
* Trim the remaining multi-string deliminator.
*/
line[strlen(line) - 1] = '\0';
add_string(&strings, line);
return;
}
/* This is output if the -h command line option is passed to the main program.
*/
void ui_module_help()
{
#ifdef DEBUG
fprintf(stderr, "%s: ui_module_help()\n", __FILE__);
#endif
printf(" Password/Group file information [-P (-%s)]:\n",
PASSWD_OPTION_ORDER);
printf("\t-l login name\t\t");
printf("\t-p encrypted password\n");
printf("\t-u user id (uid)\t");
printf("\t-g group id (gid)\n");
printf("\t-c password change time");
printf("\t-e password expire time\n");
printf("\t-d home directory\t");
printf("\t-m home directory mode\n");
printf("\t-s login shell\n");
printf("\t-i gecos (any of [n]ame,[1]st,[2]nd,[3]rd or [a]ll)\n\n");
return;
}
/* This is the equivalent to main() only without argc and argv available. */
int ui_module_exec(char ***s, const struct passwd *pw, const int multi_char,
const int verbose, char *tf)
{
char *p = options;
struct stat st;
#ifdef HAVE_GETSPNAM
struct spwd *spwd = NULL;
#endif
#ifdef DEBUG
fprintf(stderr, "%s: ui_module_exec()\n", __FILE__);
#endif
#ifdef HAVE_GETSPNAM
if (amroot) {
if ((spwd = getspnam(pw->pw_name)) == NULL)
warnx("%s", "getspnam(): unknown error");
}
#endif
strings = *s;
while (*p) {
char tmp[32];
switch (*p) {
#ifdef HAVE_GETSPNAM
case 'c':
if (!amroot) {
add_string(&strings, "!");
break;
}
snprintf(tmp, sizeof(tmp), "%li", (long) spwd->sp_max);
add_string(&strings, tmp);
break;
case 'e':
if (!amroot) {
add_string(&strings, "!");
break;
}
snprintf(tmp, sizeof(tmp), "%li", (long) spwd->sp_expire);
add_string(&strings, tmp);
break;
#else
case 'c':
snprintf(tmp, sizeof(tmp), "%li", (long) pw->pw_change);
add_string(&strings, tmp);
break;
case 'e':
snprintf(tmp, sizeof(tmp), "%li", (long) pw->pw_expire);
add_string(&strings, tmp);
break;
#endif
case 'l':
add_string(&strings, pw->pw_name);
break;
case 'd':
add_string(&strings, (pw->pw_dir && pw->pw_dir[0]) ? pw->pw_dir : "-");
break;
case 's':
add_string(&strings, (pw->pw_shell && pw->pw_shell[0]) ? pw->pw_shell : "-");
break;
case 'p':
#ifdef HAVE_GETSPNAM
if (!amroot)
add_string(&strings, (pw->pw_passwd
&& pw->pw_passwd[0]) ? pw->pw_passwd : "-");
else
add_string(&strings, (spwd->sp_pwdp
&& spwd->sp_pwdp[0]) ? spwd->sp_pwdp : "-");
#else
add_string(&strings, (pw->pw_passwd
&& pw->pw_passwd[0]) ? pw->pw_passwd : "-");
#endif
break;
case 'u':
sprintf(tmp, "%li", (long) pw->pw_uid);
add_string(&strings, tmp);
break;
case 'g':
groups(pw, multi_char, verbose);
break;
case 'm':
if (stat(pw->pw_dir, &st) == -1) {
add_string(&strings, "!");
break;
}
sprintf(tmp, "%.4o", (unsigned) st.st_mode & ALLPERMS);
add_string(&strings, tmp);
break;
case 'i':
gecos_strings(pw->pw_gecos);
break;
default:
break;
}
p++;
}
*s = strings;
return EXIT_SUCCESS;
}
char *ui_module_options_init(char **defaults)
{
*defaults = "P";
return PASSWD_OPTION_STRING;
}
/* Check module option validity. */
int ui_module_options(int argc, char **argv)
{
int opt;
char *p = options;
#ifdef DEBUG
fprintf(stderr, "%s: ui_module_options()\n", __FILE__);
#endif
while ((opt = getopt(argc, argv, PASSWD_OPTION_STRING)) != -1) {
switch (opt) {
case 'i':
gecos_options = optarg;
break;
case 'P':
case 'l':
case 'p':
case 'u':
case 'g':
case 'c':
case 'e':
case 'd':
case 's':
case 'm':
break;
case '?':
warnx("passwd: invalid option -- %c", optopt);
default:
return 1;
}
if (opt == 'i') {
if (parse_gecos_options(gecos_options))
return 1;
}
/*
* This option '-P' sets all available options for this module.
*/
if (opt == 'P') {
strncpy(options, PASSWD_OPTION_ORDER, sizeof(options));
gecos_options = "a";
break;
}
*p++ = opt;
*p = '\0';
}
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1