version 1.7, 2001/03/02 14:39:44 |
version 1.8, 2002/01/03 03:49:16 |
|
|
/* |
/* |
* Copyright (c) 1999-2000 Todd C. Miller <Todd.Miller@courtesan.com> |
* Copyright (c) 1999-2001 Todd C. Miller <Todd.Miller@courtesan.com> |
* All rights reserved. |
* All rights reserved. |
* |
* |
* Redistribution and use in source and binary forms, with or without |
* Redistribution and use in source and binary forms, with or without |
|
|
|
|
#include "config.h" |
#include "config.h" |
|
|
|
#include <sys/types.h> |
|
#include <sys/param.h> |
#include <stdio.h> |
#include <stdio.h> |
#ifdef STDC_HEADERS |
#ifdef STDC_HEADERS |
#include <stdlib.h> |
# include <stdlib.h> |
|
# include <stddef.h> |
|
#else |
|
# ifdef HAVE_STDLIB_H |
|
# include <stdlib.h> |
|
# endif |
#endif /* STDC_HEADERS */ |
#endif /* STDC_HEADERS */ |
#ifdef HAVE_UNISTD_H |
|
#include <unistd.h> |
|
#endif /* HAVE_UNISTD_H */ |
|
#ifdef HAVE_STRING_H |
#ifdef HAVE_STRING_H |
#include <string.h> |
# include <string.h> |
|
#else |
|
# ifdef HAVE_STRINGS_H |
|
# include <strings.h> |
|
# endif |
#endif /* HAVE_STRING_H */ |
#endif /* HAVE_STRING_H */ |
#ifdef HAVE_STRINGS_H |
# ifdef HAVE_UNISTD_H |
#include <strings.h> |
#include <unistd.h> |
#endif /* HAVE_STRINGS_H */ |
#endif /* HAVE_UNISTD_H */ |
#include <sys/types.h> |
#include <ctype.h> |
#include <sys/param.h> |
|
|
|
#include "sudo.h" |
#include "sudo.h" |
|
|
#ifndef lint |
#ifndef lint |
static const char rcsid[] = "$Sudo: defaults.c,v 1.23 2000/03/22 23:40:09 millert Exp $"; |
static const char rcsid[] = "$Sudo: defaults.c,v 1.38 2001/12/30 18:40:09 millert Exp $"; |
#endif /* lint */ |
#endif /* lint */ |
|
|
/* |
/* |
|
|
* Local prototypes. |
* Local prototypes. |
*/ |
*/ |
static int store_int __P((char *, struct sudo_defs_types *, int)); |
static int store_int __P((char *, struct sudo_defs_types *, int)); |
|
static int store_uint __P((char *, struct sudo_defs_types *, int)); |
static int store_str __P((char *, struct sudo_defs_types *, int)); |
static int store_str __P((char *, struct sudo_defs_types *, int)); |
static int store_syslogfac __P((char *, struct sudo_defs_types *, int)); |
static int store_syslogfac __P((char *, struct sudo_defs_types *, int)); |
static int store_syslogpri __P((char *, struct sudo_defs_types *, int)); |
static int store_syslogpri __P((char *, struct sudo_defs_types *, int)); |
static int store_mode __P((char *, struct sudo_defs_types *, int)); |
static int store_mode __P((char *, struct sudo_defs_types *, int)); |
static int store_pwflag __P((char *, struct sudo_defs_types *, int)); |
static int store_pwflag __P((char *, struct sudo_defs_types *, int)); |
|
static int store_list __P((char *, struct sudo_defs_types *, int)); |
|
static void list_op __P((char *, size_t, struct sudo_defs_types *, enum list_ops)); |
|
|
/* |
/* |
* Table describing compile-time and run-time options. |
* Table describing compile-time and run-time options. |
*/ |
*/ |
struct sudo_defs_types sudo_defs_table[] = { |
#include <def_data.c> |
{ |
|
"syslog_ifac", T_INT, NULL |
|
}, { |
|
"syslog_igoodpri", T_INT, NULL |
|
}, { |
|
"syslog_ibadpri", T_INT, NULL |
|
}, { |
|
"syslog", T_LOGFAC|T_BOOL, |
|
"Syslog facility if syslog is being used for logging: %s" |
|
}, { |
|
"syslog_goodpri", T_LOGPRI, |
|
"Syslog priority to use when user authenticates successfully: %s" |
|
}, { |
|
"syslog_badpri", T_LOGPRI, |
|
"Syslog priority to use when user authenticates unsuccessfully: %s" |
|
}, { |
|
"long_otp_prompt", T_FLAG, |
|
"Put OTP prompt on its own line" |
|
}, { |
|
"ignore_dot", T_FLAG, |
|
"Ignore '.' in $PATH" |
|
}, { |
|
"mail_always", T_FLAG, |
|
"Always send mail when sudo is run" |
|
}, { |
|
"mail_no_user", T_FLAG, |
|
"Send mail if the user is not in sudoers" |
|
}, { |
|
"mail_no_host", T_FLAG, |
|
"Send mail if the user is not in sudoers for this host" |
|
}, { |
|
"mail_no_perms", T_FLAG, |
|
"Send mail if the user is not allowed to run a command" |
|
}, { |
|
"tty_tickets", T_FLAG, |
|
"Use a separate timestamp for each user/tty combo" |
|
}, { |
|
"lecture", T_FLAG, |
|
"Lecture user the first time they run sudo" |
|
}, { |
|
"authenticate", T_FLAG, |
|
"Require users to authenticate by default" |
|
}, { |
|
"root_sudo", T_FLAG, |
|
"Root may run sudo" |
|
}, { |
|
"log_host", T_FLAG, |
|
"Log the hostname in the (non-syslog) log file" |
|
}, { |
|
"log_year", T_FLAG, |
|
"Log the year in the (non-syslog) log file" |
|
}, { |
|
"shell_noargs", T_FLAG, |
|
"If sudo is invoked with no arguments, start a shell" |
|
}, { |
|
"set_home", T_FLAG, |
|
"Set $HOME to the target user when starting a shell with -s" |
|
}, { |
|
"path_info", T_FLAG, |
|
"Allow some information gathering to give useful error messages" |
|
}, { |
|
"fqdn", T_FLAG, |
|
"Require fully-qualified hsotnames in the sudoers file" |
|
}, { |
|
"insults", T_FLAG, |
|
"Insult the user when they enter an incorrect password" |
|
}, { |
|
"requiretty", T_FLAG, |
|
"Only allow the user to run sudo if they have a tty" |
|
}, { |
|
"env_editor", T_FLAG, |
|
"Visudo will honor the EDITOR environment variable" |
|
}, { |
|
"rootpw", T_FLAG, |
|
"Prompt for root's password, not the users's" |
|
}, { |
|
"runaspw", T_FLAG, |
|
"Prompt for the runas_default user's password, not the users's" |
|
}, { |
|
"targetpw", T_FLAG, |
|
"Prompt for the target user's password, not the users's" |
|
}, { |
|
"use_loginclass", T_FLAG, |
|
"Apply defaults in the target user's login class if there is one" |
|
}, { |
|
"set_logname", T_FLAG, |
|
"Set the LOGNAME and USER environment variables" |
|
}, { |
|
"loglinelen", T_INT|T_BOOL, |
|
"Length at which to wrap log file lines (0 for no wrap): %d" |
|
}, { |
|
"timestamp_timeout", T_INT|T_BOOL, |
|
"Authentication timestamp timeout: %d minutes" |
|
}, { |
|
"passwd_timeout", T_INT|T_BOOL, |
|
"Password prompt timeout: %d minutes" |
|
}, { |
|
"passwd_tries", T_INT, |
|
"Number of tries to enter a password: %d" |
|
}, { |
|
"umask", T_MODE|T_BOOL, |
|
"Umask to use or 0777 to use user's: 0%o" |
|
}, { |
|
"logfile", T_STR|T_BOOL|T_PATH, |
|
"Path to log file: %s" |
|
}, { |
|
"mailerpath", T_STR|T_BOOL|T_PATH, |
|
"Path to mail program: %s" |
|
}, { |
|
"mailerflags", T_STR|T_BOOL, |
|
"Flags for mail program: %s" |
|
}, { |
|
"mailto", T_STR|T_BOOL, |
|
"Address to send mail to: %s" |
|
}, { |
|
"mailsub", T_STR, |
|
"Subject line for mail messages: %s" |
|
}, { |
|
"badpass_message", T_STR, |
|
"Incorrect password message: %s" |
|
}, { |
|
"timestampdir", T_STR|T_PATH, |
|
"Path to authentication timestamp dir: %s" |
|
}, { |
|
"exempt_group", T_STR|T_BOOL, |
|
"Users in this group are exempt from password and PATH requirements: %s" |
|
}, { |
|
"passprompt", T_STR, |
|
"Default password prompt: %s" |
|
}, { |
|
"runas_default", T_STR, |
|
"Default user to run commands as: %s" |
|
}, { |
|
"secure_path", T_STR|T_BOOL, |
|
"Value to override user's $PATH with: %s" |
|
}, { |
|
"editor", T_STR|T_PATH, |
|
"Path to the editor for use by visudo: %s" |
|
}, { |
|
"listpw_i", T_INT, NULL |
|
}, { |
|
"verifypw_i", T_INT, NULL |
|
}, { |
|
"listpw", T_PWFLAG, |
|
"When to require a password for 'list' pseudocommand: %s" |
|
}, { |
|
"verifypw", T_PWFLAG, |
|
"When to require a password for 'verify' pseudocommand: %s" |
|
}, { |
|
NULL, 0, NULL |
|
} |
|
}; |
|
|
|
/* |
/* |
* Print version and configure info. |
* Print version and configure info. |
|
|
dump_defaults() |
dump_defaults() |
{ |
{ |
struct sudo_defs_types *cur; |
struct sudo_defs_types *cur; |
|
struct list_member *item; |
|
|
for (cur = sudo_defs_table; cur->name; cur++) { |
for (cur = sudo_defs_table; cur->name; cur++) { |
if (cur->desc) { |
if (cur->desc) { |
|
|
putchar('\n'); |
putchar('\n'); |
} |
} |
break; |
break; |
|
case T_UINT: |
case T_INT: |
case T_INT: |
(void) printf(cur->desc, cur->sd_un.ival); |
(void) printf(cur->desc, cur->sd_un.ival); |
putchar('\n'); |
putchar('\n'); |
|
|
(void) printf(cur->desc, cur->sd_un.mode); |
(void) printf(cur->desc, cur->sd_un.mode); |
putchar('\n'); |
putchar('\n'); |
break; |
break; |
|
case T_LIST: |
|
if (cur->sd_un.list) { |
|
puts(cur->desc); |
|
for (item = cur->sd_un.list; item; item = item->next) |
|
printf("\t%s\n", item->value); |
|
} |
|
break; |
} |
} |
} |
} |
} |
} |
|
|
default: |
default: |
p = strrchr(cur->desc, ':'); |
p = strrchr(cur->desc, ':'); |
if (p) |
if (p) |
(void) printf("%s: %.*s\n", cur->name, (int)(p - cur->desc), |
(void) printf("%s: %.*s\n", cur->name, |
cur->desc); |
(int) (p - cur->desc), cur->desc); |
else |
else |
(void) printf("%s: %s\n", cur->name, cur->desc); |
(void) printf("%s: %s\n", cur->name, cur->desc); |
break; |
break; |
|
|
return(FALSE); |
return(FALSE); |
} |
} |
break; |
break; |
|
case T_UINT: |
|
if (!val) { |
|
/* Check for bogus boolean usage or lack of a value. */ |
|
if (!(cur->type & T_BOOL) || op != FALSE) { |
|
(void) fprintf(stderr, |
|
"%s: no value specified for `%s' on line %d\n", Argv[0], |
|
var, sudolineno); |
|
return(FALSE); |
|
} |
|
} |
|
if (!store_uint(val, cur, op)) { |
|
(void) fprintf(stderr, |
|
"%s: value '%s' is invalid for option '%s'\n", Argv[0], |
|
val, var); |
|
return(FALSE); |
|
} |
|
break; |
case T_MODE: |
case T_MODE: |
if (!val) { |
if (!val) { |
/* Check for bogus boolean usage or lack of a value. */ |
/* Check for bogus boolean usage or lack of a value. */ |
|
|
if (num == I_FQDN && op) |
if (num == I_FQDN && op) |
set_fqdn(); |
set_fqdn(); |
break; |
break; |
|
case T_LIST: |
|
if (!val) { |
|
/* Check for bogus boolean usage or lack of a value. */ |
|
if (!(cur->type & T_BOOL) || op != FALSE) { |
|
(void) fprintf(stderr, |
|
"%s: no value specified for `%s' on line %d\n", Argv[0], |
|
var, sudolineno); |
|
return(FALSE); |
|
} |
|
} |
|
if (!store_list(val, cur, op)) { |
|
(void) fprintf(stderr, |
|
"%s: value '%s' is invalid for option '%s'\n", Argv[0], |
|
val, var); |
|
return(FALSE); |
|
} |
} |
} |
|
|
return(TRUE); |
return(TRUE); |
|
|
def->sd_un.str = NULL; |
def->sd_un.str = NULL; |
} |
} |
break; |
break; |
|
case T_LIST: |
|
list_op(NULL, 0, def, freeall); |
|
break; |
} |
} |
} |
} |
|
|
|
|
def_flag(I_MAIL_ALWAYS) = TRUE; |
def_flag(I_MAIL_ALWAYS) = TRUE; |
#endif |
#endif |
#ifdef SEND_MAIL_WHEN_NO_USER |
#ifdef SEND_MAIL_WHEN_NO_USER |
def_flag(I_MAIL_NOUSER) = TRUE; |
def_flag(I_MAIL_NO_USER) = TRUE; |
#endif |
#endif |
#ifdef SEND_MAIL_WHEN_NO_HOST |
#ifdef SEND_MAIL_WHEN_NO_HOST |
def_flag(I_MAIL_NOHOST) = TRUE; |
def_flag(I_MAIL_NO_HOST) = TRUE; |
#endif |
#endif |
#ifdef SEND_MAIL_WHEN_NOT_OK |
#ifdef SEND_MAIL_WHEN_NOT_OK |
def_flag(I_MAIL_NOPERMS) = TRUE; |
def_flag(I_MAIL_NO_PERMS) = TRUE; |
#endif |
#endif |
#ifdef USE_TTY_TICKETS |
#ifdef USE_TTY_TICKETS |
def_flag(I_TTY_TICKETS) = TRUE; |
def_flag(I_TTY_TICKETS) = TRUE; |
|
|
#ifdef ENV_EDITOR |
#ifdef ENV_EDITOR |
def_flag(I_ENV_EDITOR) = TRUE; |
def_flag(I_ENV_EDITOR) = TRUE; |
#endif |
#endif |
def_flag(I_LOGNAME) = TRUE; |
def_flag(I_SET_LOGNAME) = TRUE; |
|
|
/* Syslog options need special care since they both strings and ints */ |
/* Syslog options need special care since they both strings and ints */ |
#if (LOGGING & SLOG_SYSLOG) |
#if (LOGGING & SLOG_SYSLOG) |
(void) store_syslogfac(LOGFAC, &sudo_defs_table[I_LOGFACSTR], TRUE); |
(void) store_syslogfac(LOGFAC, &sudo_defs_table[I_SYSLOG], TRUE); |
(void) store_syslogpri(PRI_SUCCESS, &sudo_defs_table[I_GOODPRISTR], TRUE); |
(void) store_syslogpri(PRI_SUCCESS, &sudo_defs_table[I_SYSLOG_GOODPRI], |
(void) store_syslogpri(PRI_FAILURE, &sudo_defs_table[I_BADPRISTR], TRUE); |
TRUE); |
|
(void) store_syslogpri(PRI_FAILURE, &sudo_defs_table[I_SYSLOG_BADPRI], |
|
TRUE); |
#endif |
#endif |
|
|
/* Password flags also have a string and integer component. */ |
/* Password flags also have a string and integer component. */ |
(void) store_pwflag("any", &sudo_defs_table[I_LISTPWSTR], TRUE); |
(void) store_pwflag("any", &sudo_defs_table[I_LISTPW], TRUE); |
(void) store_pwflag("all", &sudo_defs_table[I_VERIFYPWSTR], TRUE); |
(void) store_pwflag("all", &sudo_defs_table[I_VERIFYPW], TRUE); |
|
|
/* Then initialize the int-like things. */ |
/* Then initialize the int-like things. */ |
#ifdef SUDO_UMASK |
#ifdef SUDO_UMASK |
|
|
#else |
#else |
def_mode(I_UMASK) = 0777; |
def_mode(I_UMASK) = 0777; |
#endif |
#endif |
def_ival(I_LOGLEN) = MAXLOGFILELEN; |
def_ival(I_LOGLINELEN) = MAXLOGFILELEN; |
def_ival(I_TS_TIMEOUT) = TIMEOUT; |
def_ival(I_TIMESTAMP_TIMEOUT) = TIMEOUT; |
def_ival(I_PW_TIMEOUT) = PASSWORD_TIMEOUT; |
def_ival(I_PASSWD_TIMEOUT) = PASSWORD_TIMEOUT; |
def_ival(I_PW_TRIES) = TRIES_FOR_PASSWORD; |
def_ival(I_PASSWD_TRIES) = TRIES_FOR_PASSWORD; |
|
|
/* Finally do the strings */ |
/* Now do the strings */ |
def_str(I_MAILTO) = estrdup(MAILTO); |
def_str(I_MAILTO) = estrdup(MAILTO); |
def_str(I_MAILSUB) = estrdup(MAILSUBJECT); |
def_str(I_MAILSUB) = estrdup(MAILSUBJECT); |
def_str(I_BADPASS_MSG) = estrdup(INCORRECT_PASSWORD); |
def_str(I_BADPASS_MESSAGE) = estrdup(INCORRECT_PASSWORD); |
def_str(I_TIMESTAMPDIR) = estrdup(_PATH_SUDO_TIMEDIR); |
def_str(I_TIMESTAMPDIR) = estrdup(_PATH_SUDO_TIMEDIR); |
def_str(I_PASSPROMPT) = estrdup(PASSPROMPT); |
def_str(I_PASSPROMPT) = estrdup(PASSPROMPT); |
def_str(I_RUNAS_DEF) = estrdup(RUNAS_DEFAULT); |
def_str(I_RUNAS_DEFAULT) = estrdup(RUNAS_DEFAULT); |
#ifdef _PATH_SENDMAIL |
#ifdef _PATH_SUDO_SENDMAIL |
def_str(I_MAILERPATH) = estrdup(_PATH_SENDMAIL); |
def_str(I_MAILERPATH) = estrdup(_PATH_SUDO_SENDMAIL); |
def_str(I_MAILERFLAGS) = estrdup("-t"); |
def_str(I_MAILERFLAGS) = estrdup("-t"); |
#endif |
#endif |
#if (LOGGING & SLOG_FILE) |
#if (LOGGING & SLOG_FILE) |
def_str(I_LOGFILE) = estrdup(_PATH_SUDO_LOGFILE); |
def_str(I_LOGFILE) = estrdup(_PATH_SUDO_LOGFILE); |
#endif |
#endif |
#ifdef EXEMPTGROUP |
#ifdef EXEMPTGROUP |
def_str(I_EXEMPT_GRP) = estrdup(EXEMPTGROUP); |
def_str(I_EXEMPT_GROUP) = estrdup(EXEMPTGROUP); |
#endif |
#endif |
#ifdef SECURE_PATH |
|
def_str(I_SECURE_PATH) = estrdup(SECURE_PATH); |
|
#endif |
|
def_str(I_EDITOR) = estrdup(EDITOR); |
def_str(I_EDITOR) = estrdup(EDITOR); |
|
|
|
/* Finally do the lists (currently just environment tables). */ |
|
init_envtables(); |
|
|
/* |
/* |
* The following depend on the above values. |
* The following depend on the above values. |
* We use a pointer to the string so that if its |
* We use a pointer to the string so that if its |
* value changes we get the change. |
* value changes we get the change. |
*/ |
*/ |
if (user_runas == NULL) |
if (user_runas == NULL) |
user_runas = &def_str(I_RUNAS_DEF); |
user_runas = &def_str(I_RUNAS_DEFAULT); |
|
|
firsttime = 0; |
firsttime = 0; |
} |
} |
|
|
def->sd_un.ival = 0; |
def->sd_un.ival = 0; |
} else { |
} else { |
l = strtol(val, &endp, 10); |
l = strtol(val, &endp, 10); |
|
if (*endp != '\0') |
|
return(FALSE); |
|
/* XXX - should check against INT_MAX */ |
|
def->sd_un.ival = (unsigned int)l; |
|
} |
|
return(TRUE); |
|
} |
|
|
|
static int |
|
store_uint(val, def, op) |
|
char *val; |
|
struct sudo_defs_types *def; |
|
int op; |
|
{ |
|
char *endp; |
|
long l; |
|
|
|
if (op == FALSE) { |
|
def->sd_un.ival = 0; |
|
} else { |
|
l = strtol(val, &endp, 10); |
if (*endp != '\0' || l < 0) |
if (*endp != '\0' || l < 0) |
return(FALSE); |
return(FALSE); |
/* XXX - should check against INT_MAX */ |
/* XXX - should check against INT_MAX */ |
|
|
} |
} |
|
|
static int |
static int |
|
store_list(str, def, op) |
|
char *str; |
|
struct sudo_defs_types *def; |
|
int op; |
|
{ |
|
char *start, *end; |
|
|
|
/* Remove all old members. */ |
|
if (op == FALSE || op == TRUE) |
|
list_op(NULL, 0, def, freeall); |
|
|
|
/* Split str into multiple space-separated words and act on each one. */ |
|
if (op != FALSE) { |
|
end = str; |
|
do { |
|
/* Remove leading blanks, if nothing but blanks we are done. */ |
|
for (start = end; isblank(*start); start++) |
|
; |
|
if (*start == '\0') |
|
break; |
|
|
|
/* Find end position and perform operation. */ |
|
for (end = start; *end && !isblank(*end); end++) |
|
; |
|
list_op(start, end - start, def, op == '-' ? delete : add); |
|
} while (*end++ != '\0'); |
|
} |
|
return(TRUE); |
|
} |
|
|
|
static int |
store_syslogfac(val, def, op) |
store_syslogfac(val, def, op) |
char *val; |
char *val; |
struct sudo_defs_types *def; |
struct sudo_defs_types *def; |
|
|
return(FALSE); /* not found */ |
return(FALSE); /* not found */ |
|
|
/* Store both name and number. */ |
/* Store both name and number. */ |
if (def->sd_un.str) { |
if (def->sd_un.str) |
free(def->sd_un.str); |
free(def->sd_un.str); |
closelog(); |
|
} |
|
openlog(Argv[0], 0, fac->num); |
|
def->sd_un.str = estrdup(fac->name); |
def->sd_un.str = estrdup(fac->name); |
sudo_defs_table[I_LOGFAC].sd_un.ival = fac->num; |
sudo_defs_table[I_LOGFAC].sd_un.ival = fac->num; |
#else |
#else |
if (def->sd_un.str) { |
if (def->sd_un.str) |
free(def->sd_un.str); |
free(def->sd_un.str); |
closelog(); |
|
} |
|
openlog(Argv[0], 0); |
|
def->sd_un.str = estrdup("default"); |
def->sd_un.str = estrdup("default"); |
#endif /* LOG_NFACILITIES */ |
#endif /* LOG_NFACILITIES */ |
return(TRUE); |
return(TRUE); |
|
|
|
|
if (op == FALSE || !val) |
if (op == FALSE || !val) |
return(FALSE); |
return(FALSE); |
if (def == &sudo_defs_table[I_GOODPRISTR]) |
if (def == &sudo_defs_table[I_SYSLOG_GOODPRI]) |
idef = &sudo_defs_table[I_GOODPRI]; |
idef = &sudo_defs_table[I_GOODPRI]; |
else if (def == &sudo_defs_table[I_BADPRISTR]) |
else if (def == &sudo_defs_table[I_SYSLOG_BADPRI]) |
idef = &sudo_defs_table[I_BADPRI]; |
idef = &sudo_defs_table[I_BADPRI]; |
else |
else |
return(FALSE); |
return(FALSE); |
|
|
int isub, flags; |
int isub, flags; |
|
|
if (strcmp(def->name, "verifypw") == 0) |
if (strcmp(def->name, "verifypw") == 0) |
isub = I_VERIFYPW; |
isub = I_VERIFYPW_I; |
else |
else |
isub = I_LISTPW; |
isub = I_LISTPW_I; |
|
|
/* Handle !foo. */ |
/* Handle !foo. */ |
if (op == FALSE) { |
if (op == FALSE) { |
|
|
sudo_defs_table[isub].sd_un.ival = flags; |
sudo_defs_table[isub].sd_un.ival = flags; |
|
|
return(TRUE); |
return(TRUE); |
|
} |
|
|
|
static void |
|
list_op(val, len, def, op) |
|
char *val; |
|
size_t len; |
|
struct sudo_defs_types *def; |
|
enum list_ops op; |
|
{ |
|
struct list_member *cur, *prev, *tmp; |
|
|
|
if (op == freeall) { |
|
for (cur = def->sd_un.list; cur; ) { |
|
tmp = cur; |
|
cur = tmp->next; |
|
free(tmp->value); |
|
free(tmp); |
|
} |
|
def->sd_un.list = NULL; |
|
return; |
|
} |
|
|
|
for (cur = def->sd_un.list, prev = NULL; cur; prev = cur, cur = cur->next) { |
|
if ((strncmp(cur->value, val, len) == 0 && cur->value[len] == '\0')) { |
|
|
|
if (op == add) |
|
return; /* already exists */ |
|
|
|
/* Delete node */ |
|
if (prev != NULL) |
|
prev->next = cur->next; |
|
else |
|
def->sd_un.list = cur->next; |
|
free(cur->value); |
|
free(cur); |
|
break; |
|
} |
|
} |
|
|
|
/* Add new node to the head of the list. */ |
|
if (op == add) { |
|
cur = emalloc(sizeof(struct list_member)); |
|
cur->value = emalloc(len + 1); |
|
(void) memcpy(cur->value, val, len); |
|
cur->value[len] = '\0'; |
|
cur->next = def->sd_un.list; |
|
def->sd_un.list = cur; |
|
} |
} |
} |