Requires resuffling functions order they work without issues. Signed-off-by: Sami Kerola <kerolasa@xxxxxx> --- login-utils/chfn.c | 276 ++++++++++++++++++++++++++--------------------------- 1 file changed, 134 insertions(+), 142 deletions(-) diff --git a/login-utils/chfn.c b/login-utils/chfn.c index 25f7e91..35d00f9 100644 --- a/login-utils/chfn.c +++ b/login-utils/chfn.c @@ -66,14 +66,6 @@ struct finfo { 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); - /* we do not accept gecos field sizes longer than MAX_FIELD_SIZE */ #define MAX_FIELD_SIZE 256 @@ -93,99 +85,43 @@ static void __attribute__((__noreturn__)) usage(FILE *fp) exit(fp == stderr ? EXIT_FAILURE : EXIT_SUCCESS); } -int main(int argc, char **argv) +/* + * 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). + */ +static int check_gecos_string(char *msg, char *gecos) { - uid_t uid; - struct finfo oldf, newf; - int interactive; - - sanitize_env(); - setlocale(LC_ALL, ""); /* both for messages and for iscntrl() below */ - bindtextdomain(PACKAGE, LOCALEDIR); - textdomain(PACKAGE); - atexit(close_stdout); - - /* - * "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)); + unsigned int i, c; - 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 (strlen(gecos) > MAX_FIELD_SIZE) { + if (msg) + warnx(_("field %s is too long"), msg); + else + warnx(_("field is too long")); + return -1; } -#ifndef HAVE_LIBUSER - if (!(is_local(oldf.username))) - errx(EXIT_FAILURE, _("can only change local entries")); -#endif - -#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); - } + 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 (setupDefaultContext(_PATH_PASSWD)) - errx(EXIT_FAILURE, - _("can't set default context for %s"), _PATH_PASSWD); - } -#endif - -#ifdef HAVE_LIBUSER - /* If we're setuid and not really root, disallow the password change. */ - if (geteuid() != getuid() && uid != oldf.pw->pw_uid) { -#else - if (uid != 0 && uid != oldf.pw->pw_uid) { -#endif - errno = EACCES; - err(EXIT_FAILURE, _("running UID doesn't match UID of user we're " - "altering, change denied")); - } - - printf(_("Changing finger information for %s.\n"), oldf.username); - -#if !defined(HAVE_LIBUSER) && defined(CHFN_CHSH_PASSWORD) - if(!auth_pam("chfn", uid, oldf.username)) { - return EXIT_FAILURE; - } -#endif - - if (interactive) - ask_info(&oldf, &newf); - - if (!set_changed_data(&oldf, &newf)) { - printf(_("Finger information not changed.\n")); - return EXIT_SUCCESS; } - - return save_new_data(&oldf) == 0 ? EXIT_SUCCESS : EXIT_FAILURE; + return 0; } /* @@ -307,19 +243,6 @@ static void parse_passwd(struct passwd *pw, struct finfo *pinfo) } /* - * ask_info () -- - * prompt the user for the finger information and store it. - */ -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"); -} - -/* * prompt () -- * ask the user for a given field and check that the string is legal. */ @@ -357,42 +280,16 @@ static char *prompt(char *question, char *def_val) } /* - * 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). + * ask_info () -- + * prompt the user for the finger information and store it. */ -static int check_gecos_string(char *msg, char *gecos) +static void ask_info(struct finfo *oldfp, struct finfo *newfp) { - 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; - } - - 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; - } - } - return 0; + 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"); } /* @@ -476,3 +373,98 @@ static int save_new_data(struct finfo *pinfo) printf(_("Finger information changed.\n")); return 0; } + +int main(int argc, char **argv) +{ + uid_t uid; + struct finfo oldf, newf; + int interactive; + + sanitize_env(); + setlocale(LC_ALL, ""); /* both for messages and for iscntrl() below */ + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + atexit(close_stdout); + + /* + * "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); + } + +#ifndef HAVE_LIBUSER + if (!(is_local(oldf.username))) + errx(EXIT_FAILURE, _("can only change local entries")); +#endif + +#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 (setupDefaultContext(_PATH_PASSWD)) + errx(EXIT_FAILURE, + _("can't set default context for %s"), _PATH_PASSWD); + } +#endif + +#ifdef HAVE_LIBUSER + /* If we're setuid and not really root, disallow the password change. */ + if (geteuid() != getuid() && uid != oldf.pw->pw_uid) { +#else + if (uid != 0 && uid != oldf.pw->pw_uid) { +#endif + errno = EACCES; + err(EXIT_FAILURE, _("running UID doesn't match UID of user we're " + "altering, change denied")); + } + + printf(_("Changing finger information for %s.\n"), oldf.username); + +#if !defined(HAVE_LIBUSER) && defined(CHFN_CHSH_PASSWORD) + if(!auth_pam("chfn", uid, oldf.username)) { + return EXIT_FAILURE; + } +#endif + + if (interactive) + ask_info(&oldf, &newf); + + if (!set_changed_data(&oldf, &newf)) { + printf(_("Finger information not changed.\n")); + return EXIT_SUCCESS; + } + + return save_new_data(&oldf) == 0 ? EXIT_SUCCESS : EXIT_FAILURE; +} -- 2.1.3 -- To unsubscribe from this list: send the line "unsubscribe util-linux" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html