passwd-1.0.13/000075500000000000000000000000001201576122700130765ustar00rootroot00000000000000passwd-1.0.13/.gitignore000064400000000000000000000000271201576122700150650ustar00rootroot00000000000000passwd tmp wrapper *.8 passwd-1.0.13/Makefile000064400000000000000000000037711201576122700145460ustar00rootroot00000000000000# # Copyright (C) 2003-2006 Dmitry V. Levin # # Makefile for the passwd project. # # This file 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. # PROJECT = passwd VERSION = $(shell sed '/^Version: */!d;s///;q' passwd.spec) MAN8PAGES = $(PROJECT).8 TARGETS = $(PROJECT) wrapper $(MAN8PAGES) DESTDIR = libdir=/usr/lib bindir=/usr/bin sbindir=/usr/sbin mandir=/usr/share/man pamdir=/etc/pam.d facdir=/etc/control.d/facilities CPPFLAGS = -D_GNU_SOURCE -DPROJECT_VERSION=\"$(VERSION)\" CFLAGS = -pipe -Wall -Werror -W -O2 LDLIBS = -lpam $(shell test -f $(libdir)/libpam_misc.so && echo -lpam_misc) LDFLAGS = -Wl,--as-needed LN_S = ln -sf MKDIR_P = mkdir -p INSTALL = install HELP2MAN = help2man -N -s8 -i $(PROJECT).inc .PHONY: all install clean indent all: $(TARGETS) $(PROJECT).8: wrapper $(PROJECT).inc $(MKDIR_P) tmp $(LN_S) ../$< tmp/$(PROJECT) $(HELP2MAN) ./tmp/$(PROJECT) > $@ install: $(INSTALL) -pD -m755 $(PROJECT) $(DESTDIR)$(bindir)/$(PROJECT) $(INSTALL) -pD -m700 wrapper $(DESTDIR)$(sbindir)/$(PROJECT) $(INSTALL) -pD -m644 $(PROJECT).1 $(DESTDIR)$(mandir)/man1/$(PROJECT).1 $(INSTALL) -pD -m644 $(PROJECT).8 $(DESTDIR)$(mandir)/man8/$(PROJECT).8 $(INSTALL) -pD -m640 $(PROJECT).pamd $(DESTDIR)$(pamdir)/$(PROJECT) $(INSTALL) -pD -m755 $(PROJECT).control $(DESTDIR)$(facdir)/$(PROJECT) clean: $(RM) $(TARGETS) *~ core $(RM) -r tmp indent: indent *.c passwd-1.0.13/passwd.1000064400000000000000000000070461201576122700144700ustar00rootroot00000000000000.\" Hey Emacs! This file is -*- nroff -*- source. .\" (above from Rik Faith..:*) .\" Copyright (c) Andrew G. Morgan 1996, .\" Updated for Owl by Solar Designer .\" Updated for ALT Linux by Dmitry V. Levin .\" .TH PASSWD 1 "2006 Sep 4" "ALT Linux Team" "ALT Linux" .SH NAME passwd \- update a user's authentication tokens(s) .SH SYNOPSIS .B passwd [-h] [-k] [username] .SH DESCRIPTION Passwd is used to update a user's authentication token(s). Passwd is configured to work through the .BR "PAM API" . Essentially, it initializes itself as a "passwd" service with .B PAM and utilizes configured .I "password" modules to authenticate and then update a user's password. Only the superuser may update another user's password by supplying a different .BR username . .SH OPTIONS .IP \fB-k\fR This option is used to indicate that the update should only be for expired authentication tokens (passwords); the user wishes to keep their non-expired tokens as before. .IP \fB-h\fR Print short usage text and exit. .SH "Remember the following two principles" .IP \fBProtect\ your\ password\fR. Don't write down your password - memorize it. In particular, don't write it down and leave it anywhere, and don't place it in an unencrypted file! Use unrelated passwords for systems controlled by different organizations. Don't give or share your password, in particular to someone claiming to be from computer support or a vendor. Don't let anyone watch you enter your password. Don't enter your password to a computer you don't trust or if things \"look funny\"; someone may be trying to hijack your password. Use the password for a limited time and change it periodically. .IP \fBChoose\ a\ hard-to-guess\ password\fR. .I passwd will try to prevent you from choosing a really bad password, but it isn't foolproof; create your password wisely. Don't use something you'd find in a dictionary (in any language or jargon). Don't use a name (including that of a spouse, parent, child, pet, fantasy character, famous person, and location) or any variation of your personal or account name. Don't use accessible information about you (such as your phone number, license plate, or social security number) or your environment. Don't use a birthday or a simple pattern (such as \"qwerty\", \"abc\", or \"aaa\"). Don't use any of those backwards, followed by a digit, or preceded by a digit. Instead, use a mixture of upper and lower case letters, as well as digits or punctuation. When choosing a new password, make sure it's unrelated to any previous password. Use long passwords (say 8 characters long). You might use a word pair with punctuation inserted, a passphrase (an understandable sequence of words), or the first letter of each word in a passphrase. .SH "" These principles are partially enforced by the system, but only partly so. Vigilence on your part will make the system much more secure. .SH "EXIT CODE" On successful completion of its task, .B passwd will complete with exit code 0. An exit code of 1 indicates an error occurred. Textual errors are written to the standard error stream. .SH "CONFORMING TO" .br .BR Linux-PAM , .BR OpenPAM . .SH "FILES" .br .B /etc/pam.d/passwd - the .B PAM passwd configuration file. .SH "SEE ALSO" .BR pam (8), .BR pam_chauthtok (3). For more complete information on how to configure this application with .BR Linux-PAM , see the .BR "Linux-PAM System Administrators' Guide" " at" .I "/usr/share/doc/Linux-PAM*/html/Linux-PAM_SAG.html" .SH AUTHOR Andrew G. Morgan passwd-1.0.13/passwd.c000064400000000000000000000111311201576122700145400ustar00rootroot00000000000000 /* * * passwd.c * * Written for Linux-PAM by Andrew G. Morgan * Modified by Solar Designer * Modified by Dmitry V. Levin * */ #include #include #include #include #include #include #include #include #include #include #include static struct pam_conv conv = { misc_conv, NULL }; #define PASSWD_SERVICE "passwd" #define PASSWD_FAIL_DELAY 2000000 /* usec delay on failure */ static void fix_fds(void) { struct stat st; if (fstat(STDOUT_FILENO, &st) < 0) { int fd = open("/dev/null", O_WRONLY); if (fd < 0) exit(EXIT_FAILURE); if (fd != STDOUT_FILENO) { if (dup2(fd, STDOUT_FILENO) != STDOUT_FILENO) exit(EXIT_FAILURE); if (close(fd) < 0) exit(EXIT_FAILURE); } } if (fstat(STDERR_FILENO, &st) < 0) { int fd = open("/dev/null", O_WRONLY); if (fd < 0) exit(EXIT_FAILURE); if (fd != STDERR_FILENO) { if (dup2(fd, STDERR_FILENO) != STDERR_FILENO) exit(EXIT_FAILURE); if (close(fd) < 0) exit(EXIT_FAILURE); } } } static void __attribute__ ((noreturn, format(printf, 1, 2))) show_usage(const char *fmt, ...) { fprintf(stderr, "%s: ", program_invocation_short_name); va_list arg; va_start(arg, fmt); vfprintf(stderr, fmt, arg); va_end(arg); fprintf(stderr, ".\nTry `%s --help' for more information.\n", program_invocation_short_name); exit(EXIT_FAILURE); } static void __attribute__ ((__noreturn__)) show_help(void) { printf("Passwd is used to update a user's authentication token(s).\n\n" "Usage: %s [options] [username]\n\n" "Valid options and arguments are:\n" " -h or --help - print this help text and exit;\n" " -k - keep non-expired authentication tokens;\n" " username - update tokens for named user.\n", program_invocation_short_name); exit(EXIT_SUCCESS); } static int parse_pass_args(int ac, const char **av, const char **user) { int pam_flags = 0, i; *user = 0; if (ac < 1) show_usage("Insufficient arguments"); for (i = 1; i < ac; ++i) { if (av[i][0] == '-') { /* options. */ if (!strcmp(av[i], "-h") || !strcmp(av[i], "--help")) show_help(); if (av[i][1] == 'k' && !av[i][2]) pam_flags = PAM_CHANGE_EXPIRED_AUTHTOK; else show_usage("%s: Invalid option", av[i]); } else { if (*user) show_usage("%s: Too many arguments", av[i]); else *user = av[i]; } } return pam_flags; } static const char * get_user(const char *user) { uid_t uid = getuid(); struct passwd *pwent; if (!user) user = getlogin(); if (!user) pwent = getpwuid(uid); else { pwent = getpwnam(user); if (uid && (!pwent || pwent->pw_uid != uid)) { fprintf(stderr, "passwd: only superuser can give different username.\n"); exit(EXIT_FAILURE); } } endpwent(); if (!pwent || !pwent->pw_name) { fprintf(stderr, "passwd: cannot retrieve username.\n"); exit(EXIT_FAILURE); } user = strdup(pwent->pw_name); if (!user) { fprintf(stderr, "passwd: out of memory.\n"); exit(EXIT_FAILURE); } return user; } static void __attribute__ ((__noreturn__)) failure(pam_handle_t * pamh, int retval) { if (pamh) { fprintf(stderr, "passwd: %s.\n", pam_strerror(pamh, retval)); pam_end(pamh, retval); } exit(EXIT_FAILURE); } int main(int ac, const char **av) { const char *user = 0; int pam_flags, retval; pam_handle_t *pamh = 0; fix_fds(); pam_flags = parse_pass_args(ac, av, &user); user = get_user(user); setlinebuf(stdout); openlog(PASSWD_SERVICE, LOG_PID, LOG_AUTHPRIV); retval = pam_start(PASSWD_SERVICE, user, &conv, &pamh); if (PAM_SUCCESS != retval) failure(pamh, retval); #ifdef HAVE_PAM_FAIL_DELAY retval = pam_fail_delay(pamh, PASSWD_FAIL_DELAY); if (PAM_SUCCESS != retval) { fprintf(stderr, "passwd: unable to set failure delay.\n"); pam_end(pamh, retval); exit(EXIT_FAILURE); } #endif /* HAVE_PAM_FAIL_DELAY */ /* * The user is authenticated by the passwd module; * change the password(s) too. */ if (!getuid()) fprintf(stderr, "passwd: updating %s authentication tokens for user %s.\n", pam_flags ? "expired" : "all", user); retval = pam_chauthtok(pamh, pam_flags); if (PAM_SUCCESS != retval) failure(pamh, retval); /* All done. */ retval = pam_end(pamh, PAM_SUCCESS); if (PAM_SUCCESS != retval) failure(pamh, retval); /* Quit gracefully. */ fprintf(stderr, "passwd: %s authentication tokens updated successfully.\n", pam_flags ? "expired" : "all"); return PAM_SUCCESS; } passwd-1.0.13/passwd.control000064400000000000000000000014671201576122700160110ustar00rootroot00000000000000#!/bin/sh . /etc/control.d/functions BINARY=/usr/bin/passwd CONFIG=/etc/pam.d/passwd new_summary "passwd utility for updating passwords using PAM" new_fmode tcb 2711 root shadow new_fmode traditional 4711 root root new_fmode restricted 700 root root new_help tcb "Any user can change his own password using $BINARY when tcb scheme is enabled" new_help traditional "Any user can change his own password using $BINARY when tcb scheme is disabled" new_help restricted "Only root may change users passwords using $BINARY" # Backwards compatibility test "$*" = public && set - tcb control_fmode "$BINARY" "$*" || exit 1 is_builtin_mode "$*" && exit 0 new_fmode tcb_config 640 root shadow new_fmode traditional_config 600 root root new_fmode restricted_config 600 root root control_fmode "$CONFIG" "$*_config" || exit 1 passwd-1.0.13/passwd.inc000064400000000000000000000011131201576122700150660ustar00rootroot00000000000000 [NAME] passwd \- passwd wrapper [EXIT CODE] On successful completion of its task, .B passwd will complete with exit code 0. An exit code of 1 indicates an error occurred. Textual errors are written to the standard error stream. [SEE ALSO] .BR passwd (1), .BR chpasswd (8), .BR usermod (8). [AUTHOR] Written by Dmitry V. Levin [COPYRIGHT] Copyright \(co 2002, 2003, 2004 Dmitry V. Levin .br This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. passwd-1.0.13/passwd.pamd000064400000000000000000000001771201576122700152470ustar00rootroot00000000000000#%PAM-1.0 auth include system-auth account include system-auth password include system-auth session required pam_deny.so passwd-1.0.13/passwd.spec000064400000000000000000000103571201576122700152610ustar00rootroot00000000000000Name: passwd Version: 1.0.13 Release: alt1 Summary: The passwd utility for setting/changing passwords using PAM License: GPLv2+ Group: System/Base Source: passwd-%version.tar PreReq: /etc/tcb, shadow-utils >= 1:4.0.0-alt3, control BuildPreReq: libpam-devel, help2man %description This package contains a system utility (passwd) which is used to update a user's authentication token(s). %prep %setup %build %make_build CFLAGS="%optflags -W -Werror" libdir=%_libdir %install %makeinstall_std libdir=%_libdir %pre %pre_control passwd %post %post_control -s tcb passwd %files %attr(600,root,root) %verify(not mode group) %config(noreplace) %_sysconfdir/pam.d/passwd %config %_controldir/passwd %attr(700,root,root) %verify(not mode group) %_bindir/passwd %_sbindir/passwd %_mandir/man?/passwd.* %changelog * Fri Aug 24 2012 Dmitry V. Levin 1.0.13-alt1 - %_sbindir/passwd: always check seteuid return code. * Wed Jan 27 2010 Slava Semushin 1.0.12-alt3 - NMU - passwd.8: fixed NAME section for whatis (Closes: #21238) * Sat Apr 14 2007 Dmitry V. Levin 1.0.12-alt2 - Reduced macro abuse in specfile. * Mon Sep 04 2006 Dmitry V. Levin 1.0.12-alt1 - passwd.1: Cleaned up, updated references. * Sat Apr 29 2006 Dmitry V. Levin 1.0.11-alt1 - Added summary to control script. * Thu Jan 12 2006 Dmitry V. Levin 1.0.10-alt1 - Link using --as-needed option to avoid linking with unused libraries. * Mon Oct 03 2005 Dmitry V. Levin 1.0.9-alt1 - Fixed build with new Linux-PAM. - Enhanced usage and help output. * Thu Aug 11 2005 Dmitry V. Levin 1.0.8-alt1 - passwd utility: initialize system logger. - passwd wrapper: use program_invocation_short_name instead of __progname. * Wed Apr 20 2005 Dmitry V. Levin 1.0.7-alt2 - Instructed RPM to not verify permissions and group ownership of files which are controlled via control(8) facility. * Fri Feb 11 2005 Dmitry V. Levin 1.0.7-alt1 - Fixed build on x86_64 platform. * Sat Sep 25 2004 Dmitry V. Levin 1.0.6-alt1 - Updated manpage and control script. * Sun Jan 18 2004 Dmitry V. Levin 1.0.5-alt1 - passwd(8): use help2man to generate manpage from template. - wrapper: deal with compilation warnings produced by -W. * Tue Jun 17 2003 Dmitry V. Levin 1.0.4-alt1 - Fixed build with OpenPAM. - Added Linux-PAM/OpenPAM multi-build support. * Fri May 23 2003 Dmitry V. Levin 1.0.3-alt1 - PAM configuration policy enforcement. * Sun Jan 12 2003 Dmitry V. Levin 1.0.2-alt1 - Be more verbose about username we are changing auth information for. - Support "traditional" and "tcb" settings for permissions on /usr/bin/passwd and /etc/pam.d/passwd (Owl). - Keep passwd at mode "restricted" in the package, but default it to "tcb" in %%post when the package is first installed. This avoids a race and fail-open behavior (inspired by Owl). * Sun Oct 13 2002 Dmitry V. Levin 1.0.1-alt1 - Added control support for passwd. * Thu Feb 07 2002 Dmitry V. Levin 1.0.0-alt1 - Rewritten root passwd wrapper. * Fri Dec 14 2001 Dmitry V. Levin 0.64.1-ipl5mdk - Switched to tcb. * Fri Sep 07 2001 Dmitry V. Levin 0.64.1-ipl4mdk - Updated pam configuration. - Rebuilt to get more dependencies. * Tue Sep 04 2001 Dmitry V. Levin 0.64.1-ipl3mdk - Merged with RH (release 7). - passwd have been split into + %_bindir/passwd - privileged utility for users; + %_sbindir/passwd - unpriviliged utility for administrator. The code of %_bindir/passwd is rewrite of passwd utility from SimplePAMApps package. There are two diffirent manpages for these utilities now. * Fri Feb 23 2001 Dmitry V. Levin 0.64.1-ipl2mdk - Added progname patch. * Fri Oct 13 2000 Dmitry V. Levin 0.64.1-ipl1mdk - Merged with RH (release 4). - RE adaptions. * Tue Apr 4 2000 Dmitry V. Levin - 0.64.1 * Sun Oct 24 1999 Dmitry V. Levin - Fandra adaptions * Sat Apr 10 1999 Cristian Gafton - first build from the new source code base. passwd-1.0.13/wrapper.c000064400000000000000000000160271201576122700147300ustar00rootroot00000000000000 /* * * passwd wrapper - implements traditional passwd options using * real passwd utility or shadow utils. * * Copyright (C) 2002, 2004, 2005 Dmitry V. Levin * 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 #include static void __attribute__ ((__noreturn__, __format__ (__printf__, 2, 3))) failure (int errnum, const char *fmt, ...) { va_list args; fflush (stdout); fprintf (stderr, "%s: ", program_invocation_short_name); va_start (args, fmt); vfprintf (stderr, fmt, args); va_end (args); if (errnum) fprintf (stderr, ": %s", strerror (errnum)); putc ('\n', stderr); fflush (stderr); exit (EXIT_FAILURE); } static void __attribute__ ((__noreturn__)) fail_username (void) { fprintf (stderr, "%s: this operation requires username to be specified.\n", program_invocation_short_name); exit (EXIT_FAILURE); } #define OPT_STDIN 0x13 const char *argp_program_version = "passwd wrapper version " PROJECT_VERSION; const char *argp_program_bug_address = "http://bugs.altlinux.ru/"; /* Short description of program. */ static const char doc[] = "passwd wrapper implements traditional passwd options using real passwd utility or shadow utils."; /* Strings for arguments in help texts. */ static const char args_doc[] = "[USERNAME]"; /* The options we understand. */ static struct argp_option options[] = { {0, 0, 0, 0, "Valid options are:", 0}, {"delete", 'd', 0, 0, "Delete the password for the specified account", 0}, {"force", 'f', 0, 0, "Force operation", 0}, {"keep-tokens", 'k', 0, 0, "Keep non-expired authentication tokens", 0}, {"lock", 'l', 0, 0, "Lock the specified account", 0}, {"unlock", 'u', 0, 0, "Unlock the specified account", 0}, {"status", 'S', 0, 0, "Report password status on the specified account", 0}, {"stdin", OPT_STDIN, 0, 0, "Read new tokens from stdin", 1}, {0, 0, 0, 0, 0, 0} }; typedef int (*DO_FPTR) (void); DO_FPTR do_fun; static int is_keep; const char *username; static int chpasswd (const char *passwd) { FILE *fp; const char *path = "/usr/sbin/chpasswd"; if (!username) fail_username (); fp = popen (path, "w"); if (!fp) failure (errno, "popen: %s", path); if (fprintf (fp, "%s:%s\n", username, passwd) != (int)(2 + strlen (username) + strlen (passwd))) failure (errno, "fprintf"); if (pclose (fp) < 0) failure (errno, "pclose"); return EXIT_SUCCESS; } static int do_stdin (void) { size_t len; char buf[BUFSIZ]; if (!username) fail_username (); if (!fgets (buf, sizeof (buf), stdin)) failure (errno, "error reading password"); len = strlen (buf); if (len > 0 && ('\n' == buf[len - 1])) buf[len - 1] = '\0'; return chpasswd (buf); } static int do_delete (void) { return chpasswd (""); } static void __attribute__ ((__noreturn__)) lock_unlock (const char *param) { const char *path = "/usr/sbin/usermod"; size_t argc = 0; const char *argv[4]; if (!username) fail_username (); argv[argc++] = "usermod"; argv[argc++] = param; argv[argc++] = username; argv[argc] = 0; execv (path, (char *const *) argv); failure (errno, "execv: %s", path); } static int do_lock (void) { lock_unlock ("-L"); } static int do_unlock (void) { lock_unlock ("-U"); } static void __attribute__ ((__noreturn__)) getspnam_failure (void) { failure (errno, "error reading user \"%s\" shadow entry", username); } static int do_status (void) { struct passwd *pw; struct spwd *spw; const char *hash = 0, *p; if (!username) fail_username (); pw = getpwnam (username); endpwent (); if (!pw) failure (0, "user \"%s\" not found.", username); hash = pw->pw_passwd; if (!strcmp (hash, "x")) { spw = getspnam (username); if (!spw) getspnam_failure (); endspent (); hash = spw->sp_pwdp; } else if (!strcmp (hash, "*NP*")) { uid_t old_uid; old_uid = geteuid (); if (seteuid (pw->pw_uid)) getspnam_failure (); spw = getspnam (username); if (!spw) getspnam_failure (); endspent (); if (seteuid (old_uid)) getspnam_failure (); hash = spw->sp_pwdp; } if (!hash || !hash[0]) { puts ("Empty password."); return EXIT_SUCCESS; } if ('*' == hash[0] || !strcmp ("x", hash) || !strcmp ("!!", hash)) { puts ("No Password set."); return EXIT_SUCCESS; } if ('!' == hash[0]) { if (!hash[1]) { puts ("Locked Empty password."); return EXIT_SUCCESS; } printf ("Locked password, "); p = hash + 1; } else { printf ("Password set, "); p = hash; } if (!strncmp (p, "$2a$", 4)) puts ("blowfish encryption."); else if (!strncmp (p, "$1$", 3)) puts ("MD5 encryption."); else if ('_' == p[0]) puts ("BSDI encryption."); else if ('$' == p[0]) puts ("unknown encryption."); else puts ("DES encryption."); return EXIT_SUCCESS; } static int do_plain (void) { const char *path = "/usr/bin/passwd"; size_t argc = 0; const char *argv[4]; argv[argc++] = "passwd"; if (is_keep) argv[argc++] = "-k"; if (username) argv[argc++] = username; argv[argc] = 0; execv (path, (char *const *) argv); failure (errno, "execv: %s", path); } /* Parse a single option. */ static error_t parse_opt (int key, char *arg, struct argp_state *state) { switch (key) { case 'd': case 'k': case 'l': case 'u': case 'S': case OPT_STDIN: if (do_fun) { fprintf (stderr, "%s: options delete, keep-tokens, lock, unlock, status and stdin are mutually exclusive.\n", program_invocation_short_name); argp_usage (state); } } switch (key) { case 'f': /* do nothing */ break; case 'd': do_fun = do_delete; break; case 'k': is_keep = 1; do_fun = do_plain; break; case 'l': do_fun = do_lock; break; case 'u': do_fun = do_unlock; break; case 'S': do_fun = do_status; break; case OPT_STDIN: do_fun = do_stdin; break; case ARGP_KEY_ARG: if (state->arg_num == 0) /* First argument */ username = arg; else { fprintf (stderr, "%s: %s: unexpected argument.\n", program_invocation_short_name, arg); argp_usage (state); } break; default: return ARGP_ERR_UNKNOWN; } return 0; } /* Our argp parser. */ static struct argp argp = { options, parse_opt, args_doc, doc, 0, 0, 0 }; int main (int argc, char **__restrict argv) { argp_parse (&argp, argc, argv, 0, 0, 0); if (!do_fun) do_fun = do_plain; return do_fun (); }