[BACK]Return to defaults.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / sudo

Diff for /src/usr.bin/sudo/Attic/defaults.c between version 1.7 and 1.8

version 1.7, 2001/03/02 14:39:44 version 1.8, 2002/01/03 03:49:16
Line 1 
Line 1 
 /*  /*
  * 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
Line 34 
Line 34 
   
 #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 */
   
 /*  /*
Line 102 
Line 109 
  * 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.
Line 272 
Line 130 
 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) {
Line 289 
Line 148 
                         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');
Line 297 
Line 157 
                     (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;
             }              }
         }          }
     }      }
Line 321 
Line 188 
                 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;
Line 438 
Line 305 
                 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. */
Line 468 
Line 352 
             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);
Line 496 
Line 396 
                         def->sd_un.str = NULL;                          def->sd_un.str = NULL;
                     }                      }
                     break;                      break;
                   case T_LIST:
                       list_op(NULL, 0, def, freeall);
                       break;
             }              }
     }      }
   
Line 510 
Line 413 
     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;
Line 551 
Line 454 
 #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
Line 570 
Line 475 
 #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;
 }  }
Line 621 
Line 526 
         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 */
Line 646 
Line 572 
 }  }
   
 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;
Line 669 
Line 626 
         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);
Line 698 
Line 649 
   
     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);
Line 747 
Line 698 
     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) {
Line 783 
Line 734 
     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;
       }
 }  }

Legend:
Removed from v.1.7  
changed lines
  Added in v.1.8