chfn: fix coding style

Signed-off-by: Sami Kerola <kerolasa@iki.fi>
This commit is contained in:
Sami Kerola 2011-11-23 22:57:31 +01:00 committed by Sami Kerola
parent e55b7a8f2f
commit 3ca1029905
1 changed files with 345 additions and 306 deletions

View File

@ -18,181 +18,184 @@
*
* 1999-02-22 Arkadiusz Mikiewicz <misiek@pld.ORG.PL>
* - added Native Language Support
*
*/
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <pwd.h>
#include <errno.h>
#include <ctype.h>
#include <errno.h>
#include <getopt.h>
#include <pwd.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include "pamfail.h"
#include "c.h"
#include "env.h"
#include "islocal.h"
#include "nls.h"
#include "pamfail.h"
#include "setpwnam.h"
#include "strutils.h"
#include "nls.h"
#include "env.h"
#include "xalloc.h"
#include "c.h"
#ifdef HAVE_LIBSELINUX
#include <selinux/selinux.h>
#include <selinux/av_permissions.h>
#include "selinux_utils.h"
# include <selinux/selinux.h>
# include <selinux/av_permissions.h>
# include "selinux_utils.h"
#endif
static char buf[1024];
struct finfo {
struct passwd *pw;
char *username;
char *full_name;
char *office;
char *office_phone;
char *home_phone;
char *other;
struct passwd *pw;
char *username;
char *full_name;
char *office;
char *office_phone;
char *home_phone;
char *other;
};
static int parse_argv (int argc, char *argv[], struct finfo *pinfo);
static void parse_passwd (struct passwd *pw, struct finfo *pinfo);
static void ask_info (struct finfo *oldfp, struct finfo *newfp);
static char *prompt (char *question, char *def_val);
static int check_gecos_string (char *msg, char *gecos);
static int set_changed_data (struct finfo *oldfp, struct finfo *newfp);
static int save_new_data (struct finfo *pinfo);
static int parse_argv(int argc, char *argv[], struct finfo *pinfo);
static void parse_passwd(struct passwd *pw, struct finfo *pinfo);
static void ask_info(struct finfo *oldfp, struct finfo *newfp);
static char *prompt(char *question, char *def_val);
static int check_gecos_string(char *msg, char *gecos);
static int set_changed_data(struct finfo *oldfp, struct finfo *newfp);
static int save_new_data(struct finfo *pinfo);
/* we do not accept gecos field sizes longer than MAX_FIELD_SIZE */
#define MAX_FIELD_SIZE 256
static void __attribute__((__noreturn__)) usage(FILE *fp)
{
fputs(USAGE_HEADER, fp);
fprintf(fp, _(" %s [options] [username]\n"), program_invocation_short_name);
fputs(USAGE_OPTIONS, fp);
fputs(_(" -f, --full-name <full-name> real name\n"), fp);
fputs(_(" -o, --office <office> office number\n"), fp);
fputs(_(" -p, --office-phone <phone> office phone number\n"), fp);
fputs(_(" -h, --home-phone <phone> home phone number\n"), fp);
fputs(USAGE_SEPARATOR, fp);
fputs(_(" -u, --help display this help and exit\n"), fp);
fputs(_(" -v, --version output version information and exit\n"), fp);
fprintf(fp, USAGE_MAN_TAIL("chfn(1)"));
exit(fp == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
fputs(USAGE_HEADER, fp);
fprintf(fp, _(" %s [options] [username]\n"), program_invocation_short_name);
fputs(USAGE_OPTIONS, fp);
fputs(_(" -f, --full-name <full-name> real name\n"), fp);
fputs(_(" -o, --office <office> office number\n"), fp);
fputs(_(" -p, --office-phone <phone> office phone number\n"), fp);
fputs(_(" -h, --home-phone <phone> home phone number\n"), fp);
fputs(USAGE_SEPARATOR, fp);
fputs(_(" -u, --help display this help and exit\n"), fp);
fputs(_(" -v, --version output version information and exit\n"), fp);
fprintf(fp, USAGE_MAN_TAIL("chfn(1)"));
exit(fp == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
}
int main (int argc, char **argv) {
uid_t uid;
struct finfo oldf, newf;
int interactive;
int status;
int main(int argc, char **argv)
{
uid_t uid;
struct finfo oldf, newf;
int interactive;
int status;
sanitize_env();
setlocale(LC_ALL, ""); /* both for messages and for iscntrl() below */
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
sanitize_env();
setlocale(LC_ALL, ""); /* both for messages and for iscntrl() below */
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
/*
* "oldf" contains the users original finger information.
* "newf" contains the changed finger information, and contains NULL
* in fields that haven't been changed.
* in the end, "newf" is folded into "oldf".
* the reason the new finger information is not put _immediately_ into
* "oldf" is that on the command line, new finger information can
* be specified before we know what user the information is being
* specified for.
*/
uid = getuid ();
memset(&oldf, 0, sizeof(oldf));
memset(&newf, 0, sizeof (newf));
/*
* "oldf" contains the users original finger information.
* "newf" contains the changed finger information, and contains NULL
* in fields that haven't been changed.
* in the end, "newf" is folded into "oldf".
*
* the reason the new finger information is not put _immediately_
* into "oldf" is that on the command line, new finger information
* can be specified before we know what user the information is
* being specified for.
*/
uid = getuid();
memset(&oldf, 0, sizeof(oldf));
memset(&newf, 0, sizeof(newf));
interactive = parse_argv (argc, argv, &newf);
if (! newf.username) {
parse_passwd (getpwuid (uid), &oldf);
if (! oldf.username)
errx(EXIT_FAILURE, _("you (user %d) don't exist."), uid);
}
else {
parse_passwd (getpwnam (newf.username), &oldf);
if (! oldf.username)
errx(EXIT_FAILURE, _("user \"%s\" does not exist."),
newf.username);
}
interactive = parse_argv(argc, argv, &newf);
if (!newf.username) {
parse_passwd(getpwuid(uid), &oldf);
if (!oldf.username)
errx(EXIT_FAILURE, _("you (user %d) don't exist."),
uid);
} else {
parse_passwd(getpwnam(newf.username), &oldf);
if (!oldf.username)
errx(EXIT_FAILURE, _("user \"%s\" does not exist."),
newf.username);
}
if (!(is_local(oldf.username)))
errx(EXIT_FAILURE, _("can only change local entries"));
if (!(is_local(oldf.username)))
errx(EXIT_FAILURE, _("can only change local entries"));
#ifdef HAVE_LIBSELINUX
if (is_selinux_enabled() > 0) {
if(uid == 0) {
if (checkAccess(oldf.username,PASSWD__CHFN)!=0) {
security_context_t user_context;
if (getprevcon(&user_context) < 0)
user_context = NULL;
errx(EXIT_FAILURE, _("%s is not authorized to change "
"the finger info of %s"),
user_context ? : _("Unknown user context"),
oldf.username);
if (is_selinux_enabled() > 0) {
if (uid == 0) {
if (checkAccess(oldf.username, PASSWD__CHFN) != 0) {
security_context_t user_context;
if (getprevcon(&user_context) < 0)
user_context = NULL;
errx(EXIT_FAILURE,
_("%s is not authorized to change "
"the finger info of %s"),
user_context ? : _("Unknown user context"),
oldf.username);
}
}
if (setupDefaultContext("/etc/passwd"))
errx(EXIT_FAILURE,
_("can't set default context for /etc/passwd"));
}
}
if (setupDefaultContext("/etc/passwd"))
errx(EXIT_FAILURE, _("can't set default context for /etc/passwd"));
}
#endif
/* Reality check */
if (uid != 0 && uid != oldf.pw->pw_uid) {
errno = EACCES;
err(EXIT_FAILURE, NULL);
}
/* Reality check */
if (uid != 0 && uid != oldf.pw->pw_uid) {
errno = EACCES;
err(EXIT_FAILURE, NULL);
}
printf (_("Changing finger information for %s.\n"), oldf.username);
printf(_("Changing finger information for %s.\n"), oldf.username);
#ifdef REQUIRE_PASSWORD
if(uid != 0) {
pam_handle_t *pamh = NULL;
struct pam_conv conv = { misc_conv, NULL };
int retcode;
if (uid != 0) {
pam_handle_t *pamh = NULL;
struct pam_conv conv = { misc_conv, NULL };
int retcode;
retcode = pam_start("chfn", oldf.username, &conv, &pamh);
if (pam_fail_check(pamh, retcode))
exit(EXIT_FAILURE);
retcode = pam_start("chfn", oldf.username, &conv, &pamh);
if (pam_fail_check(pamh, retcode))
exit(EXIT_FAILURE);
retcode = pam_authenticate(pamh, 0);
if (pam_fail_check(pamh, retcode))
exit(EXIT_FAILURE);
retcode = pam_authenticate(pamh, 0);
if (pam_fail_check(pamh, retcode))
exit(EXIT_FAILURE);
retcode = pam_acct_mgmt(pamh, 0);
if (retcode == PAM_NEW_AUTHTOK_REQD)
retcode = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
if (pam_fail_check(pamh, retcode))
exit(EXIT_FAILURE);
retcode = pam_acct_mgmt(pamh, 0);
if (retcode == PAM_NEW_AUTHTOK_REQD)
retcode =
pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
if (pam_fail_check(pamh, retcode))
exit(EXIT_FAILURE);
retcode = pam_setcred(pamh, 0);
if (pam_fail_check(pamh, retcode))
exit(EXIT_FAILURE);
retcode = pam_setcred(pamh, 0);
if (pam_fail_check(pamh, retcode))
exit(EXIT_FAILURE);
pam_end(pamh, 0);
/* no need to establish a session; this isn't a session-oriented
* activity... */
}
#endif /* REQUIRE_PASSWORD */
pam_end(pamh, 0);
/* no need to establish a session; this isn't a
* session-oriented activity... */
}
#endif /* REQUIRE_PASSWORD */
if (interactive)
ask_info(&oldf, &newf);
if (interactive) ask_info (&oldf, &newf);
if (! set_changed_data (&oldf, &newf)) {
printf (_("Finger information not changed.\n"));
return EXIT_SUCCESS;
}
status = save_new_data (&oldf);
return status;
if (!set_changed_data(&oldf, &newf)) {
printf(_("Finger information not changed.\n"));
return EXIT_SUCCESS;
}
status = save_new_data(&oldf);
return status;
}
/*
@ -202,102 +205,116 @@ int main (int argc, char **argv) {
*/
static int parse_argv(int argc, char *argv[], struct finfo *pinfo)
{
int index, c, status;
int info_given;
int index, c, status;
int info_given;
static struct option long_options[] = {
{ "full-name", required_argument, 0, 'f' },
{ "office", required_argument, 0, 'o' },
{ "office-phone", required_argument, 0, 'p' },
{ "home-phone", required_argument, 0, 'h' },
{ "help", no_argument, 0, 'u' },
{ "version", no_argument, 0, 'v' },
{ NULL, no_argument, 0, '0' },
};
static struct option long_options[] = {
{"full-name", required_argument, 0, 'f'},
{"office", required_argument, 0, 'o'},
{"office-phone", required_argument, 0, 'p'},
{"home-phone", required_argument, 0, 'h'},
{"help", no_argument, 0, 'u'},
{"version", no_argument, 0, 'v'},
{NULL, no_argument, 0, '0'},
};
optind = 0;
info_given = false;
while (true) {
c = getopt_long (argc, argv, "f:r:p:h:o:uv", long_options, &index);
if (c == -1) break;
/* version? output version and exit. */
if (c == 'v') {
printf (UTIL_LINUX_VERSION);
exit (EXIT_SUCCESS);
optind = 0;
info_given = false;
while (true) {
c = getopt_long(argc, argv, "f:r:p:h:o:uv", long_options,
&index);
if (c == -1)
break;
/* version? output version and exit. */
if (c == 'v') {
printf(UTIL_LINUX_VERSION);
exit(EXIT_SUCCESS);
}
if (c == 'u')
usage(stdout);
/* all other options must have an argument. */
if (!optarg)
usage(stderr);
/* ok, we were given an argument */
info_given = true;
status = 0;
/* now store the argument */
switch (c) {
case 'f':
pinfo->full_name = optarg;
status = check_gecos_string(_("Name"), optarg);
break;
case 'o':
pinfo->office = optarg;
status = check_gecos_string(_("Office"), optarg);
break;
case 'p':
pinfo->office_phone = optarg;
status = check_gecos_string(_("Office Phone"), optarg);
break;
case 'h':
pinfo->home_phone = optarg;
status = check_gecos_string(_("Home Phone"), optarg);
break;
default:
usage(stderr);
}
if (status < 0)
exit(status);
}
if (c == 'u')
usage (stdout);
/* all other options must have an argument. */
if (! optarg)
usage (stderr);
/* ok, we were given an argument */
info_given = true;
status = 0;
/* now store the argument */
switch (c) {
case 'f':
pinfo->full_name = optarg;
status = check_gecos_string (_("Name"), optarg);
break;
case 'o':
pinfo->office = optarg;
status = check_gecos_string (_("Office"), optarg);
break;
case 'p':
pinfo->office_phone = optarg;
status = check_gecos_string (_("Office Phone"), optarg);
break;
case 'h':
pinfo->home_phone = optarg;
status = check_gecos_string (_("Home Phone"), optarg);
break;
default:
usage (stderr);
/* done parsing arguments. check for a username. */
if (optind < argc) {
if (optind + 1 < argc)
usage(stderr);
pinfo->username = argv[optind];
}
if (status < 0) exit (status);
}
/* done parsing arguments. check for a username. */
if (optind < argc) {
if (optind + 1 < argc)
usage (stderr);
pinfo->username = argv[optind];
}
return (! info_given);
return (!info_given);
}
/*
* parse_passwd () --
* take a struct password and fill in the fields of the
* struct finfo.
* take a struct password and fill in the fields of the struct finfo.
*/
static void parse_passwd(struct passwd *pw, struct finfo *pinfo)
{
char *gecos;
char *cp;
char *gecos;
char *cp;
if (pw) {
pinfo->pw = pw;
pinfo->username = pw->pw_name;
/* use pw_gecos - we take a copy since PAM destroys the original */
gecos = xstrdup(pw->pw_gecos);
cp = (gecos ? gecos : "");
pinfo->full_name = cp;
cp = strchr (cp, ',');
if (cp) { *cp = 0, cp++; } else return;
pinfo->office = cp;
cp = strchr (cp, ',');
if (cp) { *cp = 0, cp++; } else return;
pinfo->office_phone = cp;
cp = strchr (cp, ',');
if (cp) { *cp = 0, cp++; } else return;
pinfo->home_phone = cp;
/* extra fields contain site-specific information, and
* can not be changed by this version of chfn. */
cp = strchr (cp, ',');
if (cp) { *cp = 0, cp++; } else return;
pinfo->other = cp;
}
if (pw) {
pinfo->pw = pw;
pinfo->username = pw->pw_name;
/* use pw_gecos - we take a copy since PAM destroys the original */
gecos = xstrdup(pw->pw_gecos);
cp = (gecos ? gecos : "");
pinfo->full_name = cp;
cp = strchr(cp, ',');
if (cp) {
*cp = 0, cp++;
} else
return;
pinfo->office = cp;
cp = strchr(cp, ',');
if (cp) {
*cp = 0, cp++;
} else
return;
pinfo->office_phone = cp;
cp = strchr(cp, ',');
if (cp) {
*cp = 0, cp++;
} else
return;
pinfo->home_phone = cp;
/* extra fields contain site-specific information, and can
* not be changed by this version of chfn. */
cp = strchr(cp, ',');
if (cp) {
*cp = 0, cp++;
} else
return;
pinfo->other = cp;
}
}
/*
@ -306,11 +323,11 @@ static void parse_passwd(struct passwd *pw, struct finfo *pinfo)
*/
static void ask_info(struct finfo *oldfp, struct finfo *newfp)
{
newfp->full_name = prompt (_("Name"), oldfp->full_name);
newfp->office = prompt (_("Office"), oldfp->office);
newfp->office_phone = prompt (_("Office Phone"), oldfp->office_phone);
newfp->home_phone = prompt (_("Home Phone"), oldfp->home_phone);
printf ("\n");
newfp->full_name = prompt(_("Name"), oldfp->full_name);
newfp->office = prompt(_("Office"), oldfp->office);
newfp->office_phone = prompt(_("Office Phone"), oldfp->office_phone);
newfp->home_phone = prompt(_("Home Phone"), oldfp->home_phone);
printf("\n");
}
/*
@ -319,67 +336,74 @@ static void ask_info(struct finfo *oldfp, struct finfo *newfp)
*/
static char *prompt(char *question, char *def_val)
{
static char *blank = "none";
int len;
char *ans, *cp;
static char *blank = "none";
int len;
char *ans, *cp;
while (true) {
if (! def_val) def_val = "";
printf("%s [%s]: ", question, def_val);
*buf = 0;
if (fgets (buf, sizeof (buf), stdin) == NULL)
errx (EXIT_FAILURE, _("Aborted."));
/* remove the newline at the end of buf. */
ans = buf;
while (isspace (*ans)) ans++;
len = strlen (ans);
while (len > 0 && isspace (ans[len-1])) len--;
if (len <= 0) return NULL;
ans[len] = 0;
if (! strcasecmp (ans, blank)) return "";
if (check_gecos_string (NULL, ans) >= 0) break;
}
cp = (char *) xmalloc (len + 1);
strcpy (cp, ans);
return cp;
while (true) {
if (!def_val)
def_val = "";
printf("%s [%s]: ", question, def_val);
*buf = 0;
if (fgets(buf, sizeof(buf), stdin) == NULL)
errx(EXIT_FAILURE, _("Aborted."));
/* remove the newline at the end of buf. */
ans = buf;
while (isspace(*ans))
ans++;
len = strlen(ans);
while (len > 0 && isspace(ans[len - 1]))
len--;
if (len <= 0)
return NULL;
ans[len] = 0;
if (!strcasecmp(ans, blank))
return "";
if (check_gecos_string(NULL, ans) >= 0)
break;
}
cp = (char *)xmalloc(len + 1);
strcpy(cp, ans);
return cp;
}
/*
* check_gecos_string () --
* check that the given gecos string is legal. if it's not legal,
* output "msg" followed by a description of the problem, and
* return (-1).
* output "msg" followed by a description of the problem, and return (-1).
*/
static int check_gecos_string(char *msg, char *gecos)
{
unsigned int i, c;
unsigned int i, c;
if (strlen(gecos) > MAX_FIELD_SIZE) {
if (msg)
warnx (_("field %s is too long"), msg);
else
warnx (_("field is too long"));
return -1;
}
if (strlen(gecos) > MAX_FIELD_SIZE) {
if (msg)
warnx(_("field %s is too long"), msg);
else
warnx(_("field is too long"));
return -1;
}
for (i = 0; i < strlen (gecos); i++) {
c = gecos[i];
if (c == ',' || c == ':' || c == '=' || c == '"' || c == '\n') {
if (msg)
warnx (_("%s: '%c' is not allowed"), msg, c);
else
warnx (_("'%c' is not allowed"), c);
return -1;
for (i = 0; i < strlen(gecos); i++) {
c = gecos[i];
if (c == ',' || c == ':' || c == '=' || c == '"' || c == '\n') {
if (msg)
warnx(_("%s: '%c' is not allowed"), msg, c);
else
warnx(_("'%c' is not allowed"), c);
return -1;
}
if (iscntrl(c)) {
if (msg)
warnx(_
("%s: control characters are not allowed"),
msg);
else
warnx(_("control characters are not allowed"));
return -1;
}
}
if (iscntrl (c)) {
if (msg)
warnx (_("%s: control characters are not allowed"), msg);
else
warnx (_("control characters are not allowed"));
return -1;
}
}
return 0;
return 0;
}
/*
@ -388,18 +412,26 @@ static int check_gecos_string(char *msg, char *gecos)
*/
static int set_changed_data(struct finfo *oldfp, struct finfo *newfp)
{
int changed = false;
int changed = false;
if (newfp->full_name) {
oldfp->full_name = newfp->full_name; changed = true; }
if (newfp->office) {
oldfp->office = newfp->office; changed = true; }
if (newfp->office_phone) {
oldfp->office_phone = newfp->office_phone; changed = true; }
if (newfp->home_phone) {
oldfp->home_phone = newfp->home_phone; changed = true; }
if (newfp->full_name) {
oldfp->full_name = newfp->full_name;
changed = true;
}
if (newfp->office) {
oldfp->office = newfp->office;
changed = true;
}
if (newfp->office_phone) {
oldfp->office_phone = newfp->office_phone;
changed = true;
}
if (newfp->home_phone) {
oldfp->home_phone = newfp->home_phone;
changed = true;
}
return changed;
return changed;
}
/*
@ -409,37 +441,44 @@ static int set_changed_data(struct finfo *oldfp, struct finfo *newfp)
*/
static int save_new_data(struct finfo *pinfo)
{
char *gecos;
int len;
char *gecos;
int len;
/* null fields will confuse printf(). */
if (! pinfo->full_name) pinfo->full_name = "";
if (! pinfo->office) pinfo->office = "";
if (! pinfo->office_phone) pinfo->office_phone = "";
if (! pinfo->home_phone) pinfo->home_phone = "";
if (! pinfo->other) pinfo->other = "";
/* null fields will confuse printf(). */
if (!pinfo->full_name)
pinfo->full_name = "";
if (!pinfo->office)
pinfo->office = "";
if (!pinfo->office_phone)
pinfo->office_phone = "";
if (!pinfo->home_phone)
pinfo->home_phone = "";
if (!pinfo->other)
pinfo->other = "";
/* create the new gecos string */
len = (strlen (pinfo->full_name) + strlen (pinfo->office) +
strlen (pinfo->office_phone) + strlen (pinfo->home_phone) +
strlen (pinfo->other) + 4);
gecos = (char *) xmalloc (len + 1);
sprintf (gecos, "%s,%s,%s,%s,%s", pinfo->full_name, pinfo->office,
pinfo->office_phone, pinfo->home_phone, pinfo->other);
/* create the new gecos string */
len = (strlen(pinfo->full_name) + strlen(pinfo->office) +
strlen(pinfo->office_phone) + strlen(pinfo->home_phone) +
strlen(pinfo->other) + 4);
gecos = (char *)xmalloc(len + 1);
sprintf(gecos, "%s,%s,%s,%s,%s", pinfo->full_name, pinfo->office,
pinfo->office_phone, pinfo->home_phone, pinfo->other);
/* remove trailing empty fields (but not subfields of pinfo->other) */
if (! pinfo->other[0] ) {
while (len > 0 && gecos[len-1] == ',') len--;
gecos[len] = 0;
}
/* remove trailing empty fields (but not subfields of pinfo->other) */
if (!pinfo->other[0]) {
while (len > 0 && gecos[len - 1] == ',')
len--;
gecos[len] = 0;
}
/* write the new struct passwd to the passwd file. */
pinfo->pw->pw_gecos = gecos;
if (setpwnam (pinfo->pw) < 0) {
warn ("setpwnam");
printf( _("Finger information *NOT* changed. Try again later.\n" ));
return -1;
}
printf (_("Finger information changed.\n"));
return 0;
/* write the new struct passwd to the passwd file. */
pinfo->pw->pw_gecos = gecos;
if (setpwnam(pinfo->pw) < 0) {
warn("setpwnam");
printf(_
("Finger information *NOT* changed. Try again later.\n"));
return -1;
}
printf(_("Finger information changed.\n"));
return 0;
}