From: Todd C. Miller Date: Wed, 4 Apr 2018 15:51:05 +0000 (-0600) Subject: Add option to prune non-matching entries from cvtsudoers output with -m X-Git-Tag: SUDO_1_8_23^2~45 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=7663ae7b27d64208910307f18a686197f22faf4c;p=sudo Add option to prune non-matching entries from cvtsudoers output with -m option is used. --- diff --git a/doc/cvtsudoers.cat b/doc/cvtsudoers.cat index 7b72eb7f6..4e7283d0e 100644 --- a/doc/cvtsudoers.cat +++ b/doc/cvtsudoers.cat @@ -4,7 +4,7 @@ NNAAMMEE ccvvttssuuddooeerrss - convert between sudoers file formats SSYYNNOOPPSSIISS - ccvvttssuuddooeerrss [--eehhMMVV] [--bb _d_n] [--cc _c_o_n_f___f_i_l_e] [--dd _d_e_f_t_y_p_e_s] + ccvvttssuuddooeerrss [--eehhMMppVV] [--bb _d_n] [--cc _c_o_n_f___f_i_l_e] [--dd _d_e_f_t_y_p_e_s] [--ff _o_u_t_p_u_t___f_o_r_m_a_t] [--ii _i_n_p_u_t___f_o_r_m_a_t] [--II _i_n_c_r_e_m_e_n_t] [--mm _f_i_l_t_e_r] [--oo _o_u_t_p_u_t___f_i_l_e] [--OO _s_t_a_r_t___p_o_i_n_t] [--ss _s_e_c_t_i_o_n_s] [_i_n_p_u_t___f_i_l_e] @@ -147,6 +147,11 @@ DDEESSCCRRIIPPTTIIOONN point of 0 will disable the generation of sudoOrder attributes in the resulting LDIF file. + --pp, ----pprruunnee--mmaattcchheess + When the --mm option is also specified, ccvvttssuuddooeerrss will prune + out non-matching users, groups and hosts from matching + entries. + --ss _s_e_c_t_i_o_n_s, ----ssuupppprreessss=_s_e_c_t_i_o_n_s Suppress the output of specific _s_e_c_t_i_o_n_s of the security policy. One or more section names may be specified, @@ -182,6 +187,9 @@ DDEESSCCRRIIPPTTIIOONN oouuttppuutt__ffoorrmmaatt == _j_s_o_n | _l_d_i_f | _s_u_d_o_e_r_s See the description of the --ff command line option. + pprruunnee__mmaattcchheess == _y_e_s | _n_o + See the description of the --pp command line option. + ssuuddooeerrss__bbaassee == _d_n See the description of the --bb command line option. @@ -223,4 +231,4 @@ DDIISSCCLLAAIIMMEERR file distributed with ssuuddoo or https://www.sudo.ws/license.html for complete details. -Sudo 1.8.23 March 30, 2018 Sudo 1.8.23 +Sudo 1.8.23 April 4, 2018 Sudo 1.8.23 diff --git a/doc/cvtsudoers.man.in b/doc/cvtsudoers.man.in index 754dcac6e..de472a19a 100644 --- a/doc/cvtsudoers.man.in +++ b/doc/cvtsudoers.man.in @@ -16,7 +16,7 @@ .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.TH "CVTSUDOERS" "1" "March 30, 2018" "Sudo @PACKAGE_VERSION@" "General Commands Manual" +.TH "CVTSUDOERS" "1" "April 4, 2018" "Sudo @PACKAGE_VERSION@" "General Commands Manual" .nh .if n .ad l .SH "NAME" @@ -25,7 +25,7 @@ .SH "SYNOPSIS" .HP 11n \fBcvtsudoers\fR -[\fB\-ehMV\fR] +[\fB\-ehMpV\fR] [\fB\-b\fR\ \fIdn\fR] [\fB\-c\fR\ \fIconf_file\fR] [\fB\-d\fR\ \fIdeftypes\fR] @@ -277,6 +277,14 @@ Defaults to a starting point of 1. A starting point of 0 will disable the generation of sudoOrder attributes in the resulting LDIF file. .TP 12n +\fB\-p\fR, \fB\--prune-matches\fR +When the +\fB\-m\fR +option is also specified, +\fBcvtsudoers\fR +will prune out non-matching users, groups and hosts from +matching entries. +.TP 12n \fB\-s\fR \fIsections\fR, \fB\--suppress\fR=\fIsections\fR Suppress the output of specific \fIsections\fR @@ -340,6 +348,11 @@ See the description of the \fB\-f\fR command line option. .TP 6n +\fBprune_matches =\fR \fIyes\fR | \fIno\fR +See the description of the +\fB\-p\fR +command line option. +.TP 6n \fBsudoers_base =\fR \fIdn\fR See the description of the \fB\-b\fR diff --git a/doc/cvtsudoers.mdoc.in b/doc/cvtsudoers.mdoc.in index 4b6e2ff22..467fe8dac 100644 --- a/doc/cvtsudoers.mdoc.in +++ b/doc/cvtsudoers.mdoc.in @@ -14,7 +14,7 @@ .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" -.Dd March 30, 2018 +.Dd April 4, 2018 .Dt CVTSUDOERS 1 .Os Sudo @PACKAGE_VERSION@ .Sh NAME @@ -22,7 +22,7 @@ .Nd convert between sudoers file formats .Sh SYNOPSIS .Nm cvtsudoers -.Op Fl ehMV +.Op Fl ehMpV .Op Fl b Ar dn .Op Fl c Ar conf_file .Op Fl d Ar deftypes @@ -228,6 +228,13 @@ option for details. Defaults to a starting point of 1. A starting point of 0 will disable the generation of sudoOrder attributes in the resulting LDIF file. +.It Fl p , Fl -prune-matches +When the +.Fl m +option is also specified, +.Nm +will prune out non-matching users, groups and hosts from +matching entries. .It Fl s Ar sections , Fl -suppress Ns = Ns Ar sections Suppress the output of specific .Ar sections @@ -284,6 +291,10 @@ command line option. See the description of the .Fl f command line option. +.It Sy prune_matches = Ar yes | no +See the description of the +.Fl p +command line option. .It Sy sudoers_base = Ar dn See the description of the .Fl b diff --git a/plugins/sudoers/cvtsudoers.c b/plugins/sudoers/cvtsudoers.c index c432c572b..dbe07a545 100644 --- a/plugins/sudoers/cvtsudoers.c +++ b/plugins/sudoers/cvtsudoers.c @@ -56,7 +56,7 @@ struct cvtsudoers_filter *filters; struct sudo_user sudo_user; struct passwd *list_pw; -static const char short_opts[] = "b:c:d:ef:hi:I:m:Mo:O:s:V"; +static const char short_opts[] = "b:c:d:ef:hi:I:m:Mo:O:ps:V"; static struct option long_opts[] = { { "base", required_argument, NULL, 'b' }, { "config", required_argument, NULL, 'c' }, @@ -68,6 +68,7 @@ static struct option long_opts[] = { { "increment", required_argument, NULL, 'I' }, { "match", required_argument, NULL, 'm' }, { "match-local", no_argument, NULL, 'M' }, + { "prune-matches", no_argument, NULL, 'p' }, { "order-start", required_argument, NULL, 'O' }, { "output", required_argument, NULL, 'o' }, { "suppress", required_argument, NULL, 's' }, @@ -85,7 +86,7 @@ static struct cvtsudoers_config *cvtsudoers_conf_read(const char *conf_file); static void cvtsudoers_conf_free(struct cvtsudoers_config *conf); static int cvtsudoers_parse_defaults(char *expression); static int cvtsudoers_parse_suppression(char *expression); -static void filter_userspecs(void); +static void filter_userspecs(struct cvtsudoers_config *conf); static void filter_defaults(struct cvtsudoers_config *conf); static void alias_remove_unused(void); @@ -207,6 +208,9 @@ main(int argc, char *argv[]) usage(1); } break; + case 'p': + conf->prune_matches = true; + break; case 's': conf->supstr = optarg; break; @@ -317,7 +321,7 @@ main(int argc, char *argv[]) } /* Apply filters. */ - filter_userspecs(); + filter_userspecs(conf); filter_defaults(conf); if (filters != NULL || conf->defaults != CVT_DEFAULTS_ALL) alias_remove_unused(); @@ -355,7 +359,8 @@ static struct cvtsudoers_conf_table cvtsudoers_conf_vars[] = { { "match", CONF_STR, &cvtsudoers_config.filter }, { "defaults", CONF_STR, &cvtsudoers_config.defstr }, { "suppress", CONF_STR, &cvtsudoers_config.supstr }, - { "expand_aliases", CONF_BOOL, &cvtsudoers_config.expand_aliases } + { "expand_aliases", CONF_BOOL, &cvtsudoers_config.expand_aliases }, + { "prune_matches", CONF_BOOL, &cvtsudoers_config.prune_matches } }; /* @@ -669,86 +674,144 @@ open_sudoers(const char *sudoers, bool doedit, bool *keepopen) } static bool -userlist_matches_filter(struct member_list *userlist) +userlist_matches_filter(struct member_list *users, bool remove_nonmatching) { struct cvtsudoers_string *s; - bool matches = false; + struct member *m, *next; + bool ret = false; debug_decl(userlist_matches_filter, SUDOERS_DEBUG_UTIL) if (filters == NULL || (STAILQ_EMPTY(&filters->users) && STAILQ_EMPTY(&filters->groups))) debug_return_bool(true); - if (STAILQ_EMPTY(&filters->users)) { - struct passwd pw; + TAILQ_FOREACH_REVERSE_SAFE(m, users, member_list, entries, next) { + bool matched = false; - /* - * Only groups in filter, make a dummy user so userlist_matches() - * can do its thing. - */ - memset(&pw, 0, sizeof(pw)); - pw.pw_name = "_nobody"; - pw.pw_uid = (uid_t)-1; - pw.pw_gid = (gid_t)-1; - if (userlist_matches(&pw, userlist) == true) - matches = true; - } + if (STAILQ_EMPTY(&filters->users)) { + struct passwd pw; + + /* + * Only groups in filter, make a dummy user so userlist_matches() + * can do its thing. + */ + memset(&pw, 0, sizeof(pw)); + pw.pw_name = "_nobody"; + pw.pw_uid = (uid_t)-1; + pw.pw_gid = (gid_t)-1; - STAILQ_FOREACH(s, &filters->users, entries) { - struct passwd *pw = NULL; - if (s->str[0] == '#') { - const char *errstr; - uid_t uid = sudo_strtoid(s->str + 1, NULL, NULL, &errstr); - if (errstr == NULL) - pw = sudo_getpwuid(uid); + if (user_matches(&pw, m) == true) { + matched = true; + ret = true; + } + } else { + STAILQ_FOREACH(s, &filters->users, entries) { + struct passwd *pw = NULL; + + if (s->str[0] == '#') { + const char *errstr; + uid_t uid = sudo_strtoid(s->str + 1, NULL, NULL, &errstr); + if (errstr == NULL) + pw = sudo_getpwuid(uid); + } + if (pw == NULL) + pw = sudo_getpwnam(s->str); + if (pw == NULL) + continue; + + if (user_matches(pw, m) == true) + matched = true; + sudo_pw_delref(pw); + + /* Only need one user in the filter to match. */ + if (matched) { + ret = true; + break; + } + } + } + + if (!matched && remove_nonmatching) { + TAILQ_REMOVE(users, m, entries); + free_member(m); } - if (pw == NULL) - pw = sudo_getpwnam(s->str); - if (pw == NULL) - continue; - if (userlist_matches(pw, userlist) == true) - matches = true; - sudo_pw_delref(pw); - if (matches) - break; } - debug_return_bool(matches); + debug_return_bool(ret); } static bool -hostlist_matches_filter(struct member_list *hostlist) +hostlist_matches_filter(struct member_list *hostlist, bool remove_nonmatching) { struct cvtsudoers_string *s; - bool matches = false; + struct member *m, *next; + char *lhost, *shost; + bool ret = false; + char **shosts; + int n = 0; debug_decl(hostlist_matches_filter, SUDOERS_DEBUG_UTIL) if (filters == NULL || STAILQ_EMPTY(&filters->hosts)) debug_return_bool(true); + /* Create an array of short host names. */ STAILQ_FOREACH(s, &filters->hosts, entries) { - user_runhost = s->str; - if ((user_srunhost = strchr(user_runhost, '.')) != NULL) { - user_srunhost = strndup(user_runhost, - (size_t)(user_srunhost - user_runhost)); - if (user_srunhost == NULL) { + n++; + } + shosts = reallocarray(NULL, n, sizeof(char *)); + if (shosts == NULL) + sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory")); + n = 0; + STAILQ_FOREACH(s, &filters->hosts, entries) { + lhost = s->str; + if ((shost = strchr(lhost, '.')) != NULL) { + shost = strndup(lhost, (size_t)(shost - lhost)); + if (shost == NULL) { sudo_fatalx(U_("%s: %s"), __func__, U_("unable to allocate memory")); } } else { - user_srunhost = user_runhost; + shost = lhost; + } + shosts[n++] = shost; + } + + TAILQ_FOREACH_REVERSE_SAFE(m, hostlist, member_list, entries, next) { + bool matched = false; + n = 0; + STAILQ_FOREACH(s, &filters->hosts, entries) { + lhost = s->str; + shost = shosts[n++]; + + /* XXX - can't use netgroup_tuple with NULL pw */ + if (host_matches(NULL, lhost, shost, m) == true) + matched = true; + + /* Only need one host in the filter to match. */ + if (matched) { + ret = true; + break; + } + } + + /* Short-circuit unless removing non-matches. */ + if (!matched && remove_nonmatching) { + TAILQ_REMOVE(hostlist, m, entries); + free_member(m); } - /* XXX - can't use netgroup_tuple with NULL pw */ - if (hostlist_matches(NULL, hostlist) == true) - matches = true; - if (user_srunhost != user_runhost) - free(user_srunhost); - user_runhost = user_host; - user_srunhost = user_shost; - if (matches) - break; } - debug_return_bool(matches); + + /* Free shosts array and its contents. */ + n = 0; + STAILQ_FOREACH(s, &filters->hosts, entries) { + lhost = s->str; + shost = shosts[n++]; + if (shost != lhost) + free(shost); + } + free(shosts); + + debug_return_bool(ret == true); } /* @@ -811,7 +874,7 @@ convert_sudoers_output(const char *buf) * Apply filters to userspecs, removing non-matching entries. */ static void -filter_userspecs(void) +filter_userspecs(struct cvtsudoers_config *conf) { struct userspec *us, *next_us; struct privilege *priv, *next_priv; @@ -826,13 +889,13 @@ filter_userspecs(void) * In the future, we may want to add a prune option. */ TAILQ_FOREACH_SAFE(us, &userspecs, entries, next_us) { - if (!userlist_matches_filter(&us->users)) { + if (!userlist_matches_filter(&us->users, conf->prune_matches)) { TAILQ_REMOVE(&userspecs, us, entries); free_userspec(us); continue; } TAILQ_FOREACH_SAFE(priv, &us->privileges, entries, next_priv) { - if (!hostlist_matches_filter(&priv->hostlist)) { + if (!hostlist_matches_filter(&priv->hostlist, conf->prune_matches)) { TAILQ_REMOVE(&us->privileges, priv, entries); free_privilege(priv); } @@ -869,7 +932,7 @@ filter_defaults(struct cvtsudoers_config *conf) break; case DEFAULTS_USER: if (!ISSET(conf->defaults, CVT_DEFAULTS_USER) || - !userlist_matches_filter(def->binding)) + !userlist_matches_filter(def->binding, conf->prune_matches)) keep = false; break; case DEFAULTS_RUNAS: @@ -878,7 +941,7 @@ filter_defaults(struct cvtsudoers_config *conf) break; case DEFAULTS_HOST: if (!ISSET(conf->defaults, CVT_DEFAULTS_HOST) || - !hostlist_matches_filter(def->binding)) + !hostlist_matches_filter(def->binding, conf->prune_matches)) keep = false; break; case DEFAULTS_CMND: @@ -998,7 +1061,7 @@ done: static void usage(int fatal) { - (void) fprintf(fatal ? stderr : stdout, "usage: %s [-ehMV] [-b dn] " + (void) fprintf(fatal ? stderr : stdout, "usage: %s [-ehMpV] [-b dn] " "[-c conf_file ] [-d deftypes] [-f output_format] [-i input_format] " "[-I increment] [-m filter] [-o output_file] [-O start_point] " "[-s sections] [input_file]\n", getprogname()); @@ -1023,6 +1086,7 @@ help(void) " -M, --match-local match filter uses passwd and group databases\n" " -o, --output=output_file write converted sudoers to output_file\n" " -O, --order-start=num starting point for first sudoOrder\n" + " -p, --prune-matches prune non-matching users, groups and hosts\n" " -s, --suppress=sections suppress output of certain sections\n" " -V, --version display version information and exit")); exit(0); diff --git a/plugins/sudoers/cvtsudoers.h b/plugins/sudoers/cvtsudoers.h index 499382127..cc3b4462b 100644 --- a/plugins/sudoers/cvtsudoers.h +++ b/plugins/sudoers/cvtsudoers.h @@ -58,6 +58,7 @@ struct cvtsudoers_config { short suppress; bool expand_aliases; bool store_options; + bool prune_matches; char *sudoers_base; char *input_format; char *output_format; @@ -67,7 +68,7 @@ struct cvtsudoers_config { }; /* Initial config settings for above. */ -#define INITIAL_CONFIG { 1, 1, CVT_DEFAULTS_ALL, 0, false, true } +#define INITIAL_CONFIG { 1, 1, CVT_DEFAULTS_ALL, 0, false, true, false } #define CONF_BOOL 0 #define CONF_UINT 1 diff --git a/plugins/sudoers/match.c b/plugins/sudoers/match.c index e67809a53..1ccbc1f0a 100644 --- a/plugins/sudoers/match.c +++ b/plugins/sudoers/match.c @@ -89,6 +89,48 @@ static bool digest_matches(int fd, const char *file, const struct sudo_digest *s */ #define has_meta(s) (strpbrk(s, "\\?*[]") != NULL) +/* + * Check whether user described by pw matches member. + * Returns ALLOW, DENY or UNSPEC. + */ +int +user_matches(const struct passwd *pw, const struct member *m) +{ + struct alias *a; + int matched = UNSPEC; + debug_decl(user_matches, SUDOERS_DEBUG_MATCH) + + switch (m->type) { + case ALL: + matched = !m->negated; + break; + case NETGROUP: + if (netgr_matches(m->name, + def_netgroup_tuple ? user_runhost : NULL, + def_netgroup_tuple ? user_srunhost : NULL, pw->pw_name)) + matched = !m->negated; + break; + case USERGROUP: + if (usergr_matches(m->name, pw->pw_name, pw)) + matched = !m->negated; + break; + case ALIAS: + if ((a = alias_get(m->name, USERALIAS)) != NULL) { + int rc = userlist_matches(pw, &a->members); + if (rc != UNSPEC) + matched = m->negated ? !rc : rc; + alias_put(a); + break; + } + /* FALLTHROUGH */ + case WORD: + if (userpw_matches(m->name, pw->pw_name, pw)) + matched = !m->negated; + break; + } + debug_return_int(matched); +} + /* * Check for user described by pw in a list of members. * Returns ALLOW, DENY or UNSPEC. @@ -97,40 +139,11 @@ int userlist_matches(const struct passwd *pw, const struct member_list *list) { struct member *m; - struct alias *a; - int rc, matched = UNSPEC; + int matched = UNSPEC; debug_decl(userlist_matches, SUDOERS_DEBUG_MATCH) TAILQ_FOREACH_REVERSE(m, list, member_list, entries) { - switch (m->type) { - case ALL: - matched = !m->negated; - break; - case NETGROUP: - if (netgr_matches(m->name, - def_netgroup_tuple ? user_runhost : NULL, - def_netgroup_tuple ? user_srunhost : NULL, pw->pw_name)) - matched = !m->negated; - break; - case USERGROUP: - if (usergr_matches(m->name, pw->pw_name, pw)) - matched = !m->negated; - break; - case ALIAS: - if ((a = alias_get(m->name, USERALIAS)) != NULL) { - rc = userlist_matches(pw, &a->members); - if (rc != UNSPEC) - matched = m->negated ? !rc : rc; - alias_put(a); - break; - } - /* FALLTHROUGH */ - case WORD: - if (userpw_matches(m->name, pw->pw_name, pw)) - matched = !m->negated; - break; - } - if (matched != UNSPEC) + if ((matched = user_matches(pw, m)) != UNSPEC) break; } debug_return_int(matched); @@ -256,46 +269,72 @@ runaslist_matches(const struct member_list *user_list, } /* - * Check for host and shost in a list of members. + * Check for lhost and shost in a list of members. * Returns ALLOW, DENY or UNSPEC. */ -int -hostlist_matches(const struct passwd *pw, const struct member_list *list) +static int +hostlist_matches_int(const struct passwd *pw, const char *lhost, + const char *shost, const struct member_list *list) { struct member *m; - struct alias *a; - int rc, matched = UNSPEC; + int matched = UNSPEC; debug_decl(hostlist_matches, SUDOERS_DEBUG_MATCH) TAILQ_FOREACH_REVERSE(m, list, member_list, entries) { - switch (m->type) { - case ALL: + matched = host_matches(pw, lhost, shost, m); + if (matched != UNSPEC) + break; + } + debug_return_int(matched); +} + +/* + * Check for user_runhost and user_srunhost in a list of members. + * Returns ALLOW, DENY or UNSPEC. + */ +int +hostlist_matches(const struct passwd *pw, const struct member_list *list) +{ + return hostlist_matches_int(pw, user_runhost, user_srunhost, list); +} + +/* + * Check whether host or shost matches member. + * Returns ALLOW, DENY or UNSPEC. + */ +int +host_matches(const struct passwd *pw, const char *lhost, const char *shost, + const struct member *m) +{ + struct alias *a; + int matched = UNSPEC; + debug_decl(host_matches, SUDOERS_DEBUG_MATCH) + + switch (m->type) { + case ALL: + matched = !m->negated; + break; + case NETGROUP: + if (netgr_matches(m->name, lhost, shost, + def_netgroup_tuple ? pw->pw_name : NULL)) matched = !m->negated; + break; + case NTWKADDR: + if (addr_matches(m->name)) + matched = !m->negated; + break; + case ALIAS: + if ((a = alias_get(m->name, HOSTALIAS)) != NULL) { + int rc = hostlist_matches_int(pw, lhost, shost, &a->members); + if (rc != UNSPEC) + matched = m->negated ? !rc : rc; + alias_put(a); break; - case NETGROUP: - if (netgr_matches(m->name, user_runhost, user_srunhost, - def_netgroup_tuple ? pw->pw_name : NULL)) - matched = !m->negated; - break; - case NTWKADDR: - if (addr_matches(m->name)) - matched = !m->negated; - break; - case ALIAS: - if ((a = alias_get(m->name, HOSTALIAS)) != NULL) { - rc = hostlist_matches(pw, &a->members); - if (rc != UNSPEC) - matched = m->negated ? !rc : rc; - alias_put(a); - break; - } - /* FALLTHROUGH */ - case WORD: - if (hostname_matches(user_srunhost, user_runhost, m->name)) - matched = !m->negated; - break; - } - if (matched != UNSPEC) + } + /* FALLTHROUGH */ + case WORD: + if (hostname_matches(shost, lhost, m->name)) + matched = !m->negated; break; } debug_return_int(matched); diff --git a/plugins/sudoers/parse.h b/plugins/sudoers/parse.h index 91555af91..f3dfaef6c 100644 --- a/plugins/sudoers/parse.h +++ b/plugins/sudoers/parse.h @@ -286,8 +286,10 @@ bool usergr_matches(const char *group, const char *user, const struct passwd *pw bool userpw_matches(const char *sudoers_user, const char *user, const struct passwd *pw); int cmnd_matches(const struct member *m); int cmndlist_matches(const struct member_list *list); +int host_matches(const struct passwd *pw, const char *host, const char *shost, const struct member *m); int hostlist_matches(const struct passwd *pw, const struct member_list *list); int runaslist_matches(const struct member_list *user_list, const struct member_list *group_list, struct member **matching_user, struct member **matching_group); +int user_matches(const struct passwd *pw, const struct member *m); int userlist_matches(const struct passwd *pw, const struct member_list *list); const char *sudo_getdomainname(void);