"Fossies" - the Fresh Open Source Software Archive

Member "userinfo-2.5/src/modules/passwd.c" (15 Jan 2015, 9091 Bytes) of package /linux/privat/userinfo-2.5.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "passwd.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.4_vs_2.5.

    1 /*
    2     Copyright (C) 2001-2015 Ben Kibbey <bjk@luxsci.net>
    3 
    4     This program is free software; you can redistribute it and/or modify
    5     it under the terms of the GNU General Public License as published by
    6     the Free Software Foundation; either version 2 of the License, or
    7     (at your option) any later version.
    8 
    9     This program is distributed in the hope that it will be useful,
   10     but WITHOUT ANY WARRANTY; without even the implied warranty of
   11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   12     GNU General Public License for more details.
   13 
   14     You should have received a copy of the GNU General Public License
   15     along with this program; if not, write to the Free Software
   16     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02110-1301  USA
   17 */
   18 #ifdef HAVE_CONFIG_H
   19 #include <config.h>
   20 #endif
   21 
   22 #include <stdio.h>
   23 #include <stdlib.h>
   24 #include <unistd.h>
   25 #include <sys/stat.h>
   26 #include <sys/types.h>
   27 #include <pwd.h>
   28 #include <grp.h>
   29 #include <errno.h>
   30 
   31 #ifdef HAVE_LIMITS_H
   32 #include <limits.h>
   33 #ifndef LINE_MAX
   34 #ifdef _POSIX2_LINE_MAX
   35 #define LINE_MAX _POSIX2_LINE_MAX
   36 #else
   37 #define LINE_MAX 2048
   38 #endif
   39 #endif
   40 #endif
   41 
   42 #ifdef HAVE_GETOPT_H
   43 #include <getopt.h>
   44 #endif
   45 
   46 #ifdef HAVE_STRING_H
   47 #include <string.h>
   48 #endif
   49 
   50 #ifdef HAVE_GETSPNAM
   51 #include <shadow.h>
   52 #endif
   53 
   54 #ifdef HAVE_ERR_H
   55 #include <err.h>
   56 #endif
   57 
   58 #ifndef HAVE_STRSEP
   59 #include "../strsep.c"
   60 #endif
   61 
   62 #ifndef HAVE_ERR_H
   63 #include "../err.c"
   64 #endif
   65 
   66 #ifdef WITH_DMALLOC
   67 #include <dmalloc.h>
   68 #endif
   69 
   70 #ifndef ALLPERMS
   71 #define ALLPERMS (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)
   72 #endif
   73 
   74 /* This is the order of options when the 'P' option is specified. It selects
   75  * all available options. */
   76 #define PASSWD_OPTION_ORDER "lpugicedsm"
   77 #define PASSWD_OPTION_STRING    "Plpugcedsmi:"
   78 
   79 static int amroot;
   80 static char **strings;
   81 static char options[11];    /* NULL terminated. */
   82 static char *gecos_options;
   83 
   84 void add_string(char ***, const char *);
   85 char *stamp(time_t, const char *);
   86 char *safe_strncat(char *, const char *, size_t);
   87 
   88 void ui_module_init(int *chainable)
   89 {
   90     /*
   91      * Keep the password file open if possible (*BSD). 
   92      */
   93 #ifdef HAVE_SETPASSENT
   94     setpassent(1);
   95 #endif
   96 
   97     if (getuid() == 0)
   98     amroot = 1;
   99 
  100     *chainable = 0;
  101 }
  102 
  103 void ui_module_exit()
  104 {
  105 #ifdef HAVE_GETSPNAM
  106     if (amroot)
  107     endspent();
  108 #endif
  109 
  110     endpwent();
  111 #ifdef HAVE_GETGRENT
  112     endgrent();
  113 #endif
  114 }
  115 
  116 /* See if the gecos options are valid. */
  117 static int parse_gecos_options(const char *args)
  118 {
  119     int i = 0;
  120 
  121     for (i = 0; i < strlen(args); i++) {
  122     switch (args[i]) {
  123         case 'n':
  124         case '1':
  125         case '2':
  126         case '3':
  127         case 'a':
  128         break;
  129         default:
  130         return 1;
  131     }
  132     }
  133 
  134     return 0;
  135 }
  136 
  137 /* Break up the gecos string into sections and add the sections to the output
  138  * string array if needed. */
  139 static void gecos_strings(char *str)
  140 {
  141     int i = 0;
  142     char *buf;
  143     const char *name, *first, *second, *third;
  144 
  145     name = first = second = third = "-";
  146 
  147     while ((buf = strsep(&str, ",")) != NULL) {
  148     if (!buf[0])
  149         continue;
  150 
  151     switch (i++) {
  152         case 0:
  153         name = buf;
  154         break;
  155         case 1:
  156         first = buf;
  157         break;
  158         case 2:
  159         second = buf;
  160         break;
  161         case 3:
  162         third = buf;
  163         break;
  164         default:
  165         break;
  166     }
  167     }
  168 
  169     for (i = 0; i < strlen(gecos_options); i++) {
  170     switch (gecos_options[i]) {
  171         case 'n':
  172         add_string(&strings, name);
  173         break;
  174         case '1':
  175         add_string(&strings, first);
  176         break;
  177         case '2':
  178         add_string(&strings, second);
  179         break;
  180         case '3':
  181         add_string(&strings, third);
  182         break;
  183         case 'a':
  184         add_string(&strings, name);
  185         add_string(&strings, first);
  186         add_string(&strings, second);
  187         add_string(&strings, third);
  188         break;
  189         default:
  190         break;
  191     }
  192     }
  193 }
  194 
  195 /* Get all groups that a user is a member of. The primary group will be the
  196  * first added. */
  197 static void groups(const struct passwd *pw, const int multi,
  198            const int verbose)
  199 {
  200     struct group *grp;
  201     char tmp[255];
  202     char line[LINE_MAX];
  203     gid_t primary = -1;
  204 
  205     line[0] = '\0';
  206 
  207     if ((grp = getgrgid(pw->pw_gid)) == NULL) {
  208     snprintf(tmp, sizeof(tmp), "%li%s%s%s", (long) pw->pw_gid,
  209          (verbose) ? "(" : "", (verbose) ? "!" : "",
  210          (verbose) ? ")" : "");
  211     add_string(&strings, tmp);
  212     return;
  213     }
  214 
  215     primary = grp->gr_gid;
  216     snprintf(tmp, sizeof(tmp), "%li%s%s%s%c", (long) pw->pw_gid,
  217          (verbose) ? "(" : "", (verbose) ? grp->gr_name : "",
  218          (verbose) ? ")" : "", multi);
  219     safe_strncat(line, tmp, sizeof(line));
  220 #ifdef HAVE_GETGRENT
  221 #ifdef HAVE_SETGROUPENT
  222     setgroupent(1);
  223 #else
  224     setgrent();
  225 #endif
  226 
  227     while ((grp = getgrent()) != NULL) {
  228     char **members = grp->gr_mem;
  229 
  230     while (*members) {
  231         if (strcmp(*members++, pw->pw_name) == 0) {
  232         if (grp->gr_gid == primary)
  233             continue;
  234 
  235         snprintf(tmp, sizeof(tmp), "%li%s%s%s%c", (long) grp->gr_gid,
  236              (verbose) ? "(" : "", (verbose) ? grp->gr_name : "",
  237              (verbose) ? ")" : "", multi);
  238         safe_strncat(line, tmp, sizeof(line));
  239         }
  240     }
  241     }
  242 #endif
  243 
  244     /*
  245      * Trim the remaining multi-string deliminator.
  246      */
  247     line[strlen(line) - 1] = '\0';
  248 
  249     add_string(&strings, line);
  250 }
  251 
  252 /* This is output if the -h command line option is passed to the main program.
  253  */
  254 void ui_module_help()
  255 {
  256     printf("  Password/Group file information [-P (-%s)]:\n",
  257        PASSWD_OPTION_ORDER);
  258     printf("\t-l  login name\t\t");
  259     printf("\t-p  encrypted password\n");
  260     printf("\t-u  user id (uid)\t");
  261     printf("\t-g  group id (gid)\n");
  262     printf("\t-c  password change time");
  263     printf("\t-e  password expire time\n");
  264     printf("\t-d  home directory\t");
  265     printf("\t-m  home directory mode\n");
  266     printf("\t-s  login shell\n");
  267     printf("\t-i  gecos (any of [n]ame,[1]st,[2]nd,[3]rd or [a]ll)\n\n");
  268 }
  269 
  270 /* This is the equivalent to main() only without argc and argv available. */
  271 int ui_module_exec(char ***s, const struct passwd *pw, const int multi_char,
  272         const int verbose, char *tf)
  273 {
  274     char *p = options;
  275     struct stat st;
  276 
  277 #ifdef HAVE_GETSPNAM
  278     struct spwd *spwd = NULL;
  279 #endif
  280 
  281 #ifdef HAVE_GETSPNAM
  282     if (amroot) {
  283     if ((spwd = getspnam(pw->pw_name)) == NULL)
  284         warnx("%s", "getspnam(): unknown error");
  285     }
  286 #endif
  287 
  288     strings = *s;
  289 
  290     while (*p) {
  291     char tmp[256];
  292 
  293     switch (*p) {
  294 #ifdef HAVE_GETSPNAM
  295         case 'c':
  296         if (!amroot || !spwd) {
  297             add_string(&strings, "!");
  298             break;
  299         }
  300 
  301         snprintf(tmp, sizeof(tmp), "%li", (long) spwd->sp_max);
  302         add_string(&strings, tmp);
  303         break;
  304         case 'e':
  305         if (!amroot || !spwd) {
  306             add_string(&strings, "!");
  307             break;
  308         }
  309 
  310         snprintf(tmp, sizeof(tmp), "%li", (long) spwd->sp_expire);
  311         add_string(&strings, tmp);
  312         break;
  313 #else
  314         case 'c':
  315 #ifdef HAVE_PASSWD_CHANGE
  316         snprintf(tmp, sizeof(tmp), "%li", (long) pw->pw_change);
  317         add_string(&strings, tmp);
  318 #else
  319         add_string(&strings, "!");
  320 #endif
  321         break;
  322         case 'e':
  323 #ifdef HAVE_PASSWD_EXPIRE
  324         snprintf(tmp, sizeof(tmp), "%li", (long) pw->pw_expire);
  325         add_string(&strings, tmp);
  326 #else
  327         add_string(&strings, "!");
  328 #endif
  329         break;
  330 #endif
  331         case 'l':
  332         add_string(&strings, pw->pw_name);
  333         break;
  334         case 'd':
  335         add_string(&strings, (pw->pw_dir && pw->pw_dir[0]) ? pw->pw_dir : "-");
  336         break;
  337         case 's':
  338         add_string(&strings, (pw->pw_shell && pw->pw_shell[0]) ? pw->pw_shell : "-");
  339         break;
  340         case 'p':
  341 #ifdef HAVE_GETSPNAM
  342         if (!amroot)
  343             add_string(&strings, (pw->pw_passwd
  344                 && pw->pw_passwd[0]) ? pw->pw_passwd : "-");
  345         else if (!spwd)
  346             add_string(&strings, "-");
  347                 else
  348             add_string(&strings, (spwd->sp_pwdp
  349                 && spwd->sp_pwdp[0]) ? spwd->sp_pwdp : "-");
  350 #else
  351         add_string(&strings, (pw->pw_passwd
  352                 && pw->pw_passwd[0]) ? pw->pw_passwd : "-");
  353 #endif
  354         break;
  355         case 'u':
  356         sprintf(tmp, "%li", (long) pw->pw_uid);
  357         add_string(&strings, tmp);
  358         break;
  359         case 'g':
  360         groups(pw, multi_char, verbose);
  361         break;
  362         case 'm':
  363         if (!pw->pw_dir || !*pw->pw_dir || stat(pw->pw_dir, &st) == -1) {
  364             add_string(&strings, "!");
  365             break;
  366         }
  367 
  368         sprintf(tmp, "%.4o", (unsigned) st.st_mode & ALLPERMS);
  369         add_string(&strings, tmp);
  370         break;
  371         case 'i':
  372 #ifdef HAVE_PASSWD_GECOS
  373         gecos_strings(pw->pw_gecos);
  374 #else
  375         add_string(&strings, "!");
  376 #endif
  377         break;
  378         default:
  379         break;
  380     }
  381 
  382     p++;
  383     }
  384 
  385     *s = strings;
  386     return EXIT_SUCCESS;
  387 }
  388 
  389 char *ui_module_options_init(char **defaults)
  390 {
  391     *defaults = "P";
  392     return PASSWD_OPTION_STRING;
  393 }
  394 
  395 /* Check module option validity. */
  396 int ui_module_options(int argc, char **argv)
  397 {
  398     int opt;
  399     char *p = options;
  400 
  401     while ((opt = getopt(argc, argv, PASSWD_OPTION_STRING)) != -1) {
  402     switch (opt) {
  403         case 'i':
  404         if (parse_gecos_options(optarg))
  405             return 1;
  406 
  407         gecos_options = optarg;
  408         break;
  409         case 'P':
  410         strncpy(options, PASSWD_OPTION_ORDER, sizeof(options));
  411         gecos_options = "a";
  412         return 0;
  413         case 'l':
  414         case 'p':
  415         case 'u':
  416         case 'g':
  417         case 'c':
  418         case 'e':
  419         case 'd':
  420         case 's':
  421         case 'm':
  422         break;
  423         case '?':
  424         warnx("passwd: invalid option -- %c", optopt);
  425         default:
  426         return 1;
  427     }
  428 
  429     *p++ = opt;
  430     *p = '\0';
  431     }
  432 
  433     return 0;
  434 }