/* Copyright (C) 2001-2006 Ben Kibbey 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 #include #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include #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; }