+1999-12-06 Ken Raeburn <raeburn@mit.edu>
+
+ * configure.in: Check for setenv. Set SETENVOBJ to setenv.o if
+ it's not available, empty otherwise.
+
1999-12-03 Danilo Almeida <dalmeida@mit.edu>
* Makefile.in: Add kvno to Windows build.
AC_PROG_INSTALL
KRB5_BUILD_PROGRAM
AC_HEADER_STDARG
-AC_CHECK_FUNCS(getusershell lstat )
+AC_CHECK_FUNCS(getusershell lstat setenv)
+if test $ac_cv_func_setenv = no ; then
+ SETENVOBJ=setenv.o
+else
+ SETENVOBJ=
+fi
+AC_SUBST(SETENVOBJ)
AC_CHECK_HEADERS(unistd.h pwd.h)
case $krb5_cv_host in
alpha-dec-osf*)
+1999-12-02 Ken Raeburn <raeburn@mit.edu>
+
+ * krb_auth_su.c (krb5_get_tkt_via_passwd): Check length of
+ principal name before copying to fixed-size buffer.
+
+ * ccache.c (krb5_ccache_filter): Fix speling error.
+ (krb5_get_login_princ): Check length of home directory pathname.
+
+ * setenv.c: New file, copied from appl/bsd.
+ * Makefile.in (OBJS): Add @SETENVOBJ@.
+ (SRCS): Add setenv.c.
+
+ * xmalloc.c: New file, providing versions of malloc, calloc,
+ realloc, and strdup that print messages and exit if memory
+ allocation fails.
+ * ksu.h (xmalloc, xrealloc, xcalloc, xstrdup): Declare.
+ * Makefile.in (SRCS, OBJS): Use it.
+ * authorization.c, ccache.c, heuristic.c, main.c: Change all calls
+ to malloc, calloc, realloc, and strdup to call x* versions if the
+ return value is not checked before use.
+
+ * authorization.c (auth_cleanup): Ditch int arguments, check for
+ null pointers instead.
+ (krb5_authorization): Update calls. Initialize file pointers to
+ null.
+ (init_auth_names): Check for buffer overflow.
+ (fcmd_resolve): Ensure enough buffer space is allocated.
+ (find_first_cmd_that_exists): Likewise. Use strcat instead of
+ sprintf'ing a buffer into itself.
+
+ * krb_auth_su.c (dump_principal, plain_dump_principal): Reformat
+ slightly.
+
+ * main.c (cc_source_tag, cc_source_tag_tmp): Now point to const.
+ (main): Unset environment variable KRB5_CONFIG. Delete -C
+ option. Force an error if lifetime strings are over 14
+ characters. Fix error message string if setluid fails. Cast pid
+ to long for printing. Call krb5_init_secure_context instead of
+ krb5_init_context and krb5_secure_config_files.
+ (main): Fix speling error.
+ (ontty): Check string size.
+ (get_dir_of_file): Argument now points to const.
+ * ksu.h (get_dir_of_file): Update declaration.
+
1999-10-26 Tom Yu <tlyu@mit.edu>
* Makefile.in: Clean up usage of CFLAGS, CPPFLAGS, DEFS, DEFINES,
$(srcdir)/ccache.c \
$(srcdir)/authorization.c \
$(srcdir)/main.c \
- $(srcdir)/heuristic.c
+ $(srcdir)/heuristic.c \
+ $(srcdir)/xmalloc.c \
+ $(srcdir)/setenv.c
OBJS = \
krb_auth_su.o \
ccache.o \
authorization.o \
main.o \
- heuristic.o
+ heuristic.o \
+ xmalloc.o \
+ @SETENVOBJ@
all:: ksu
#include "ksu.h"
-static void auth_cleanup PROTOTYPE((int, FILE *, int, FILE *, char *));
+static void auth_cleanup PROTOTYPE((FILE *, FILE *, char *));
krb5_boolean fowner(fp, uid)
FILE *fp;
int k5login_flag =0;
int k5users_flag =0;
krb5_boolean retbool =FALSE;
- FILE * login_fp, * users_fp;
+ FILE * login_fp = 0, * users_fp = 0;
krb5_error_code retval = 0;
- struct stat statbuf;
struct stat st_temp;
*ok =FALSE;
}else{
if(retval = k5users_lookup(users_fp,princname,
cmd,&retbool,out_fcmd)){
- auth_cleanup(k5users_flag,users_fp,
- k5login_flag,login_fp, princname);
+ auth_cleanup(users_fp, login_fp, princname);
return retval;
}else{
*ok =retbool;
"In krb5_authorization: principal to be authorized %s\n",
princname);
if (retval = k5login_lookup( login_fp, princname, &retbool)){
- auth_cleanup(k5users_flag,users_fp,
- k5login_flag,login_fp, princname);
+ auth_cleanup(users_fp, login_fp, princname);
return retval;
}
if (retbool) {
if (cmd)
- *out_fcmd = strdup(cmd);
+ *out_fcmd = xstrdup(cmd);
}
}
if ((!k5users_flag) && (retbool == FALSE) ){
if(retval = k5users_lookup (users_fp, princname,
cmd, &retbool, out_fcmd)){
- auth_cleanup(k5users_flag,users_fp,
- k5login_flag,login_fp, princname);
+ auth_cleanup(users_fp, login_fp, princname);
return retval;
}
}
if (k5login_flag && k5users_flag){
- char * kuser = (char *) calloc (strlen(princname), sizeof(char));
+ char * kuser = (char *) xcalloc (strlen(princname), sizeof(char));
if (!(krb5_aname_to_localname(context, principal,
strlen(princname), kuser))
&& (strcmp(kuser, luser) == 0)) {
}
*ok =retbool;
- auth_cleanup(k5users_flag,users_fp, k5login_flag,login_fp, princname);
+ auth_cleanup(users_fp, login_fp, princname);
return 0;
}
if ((fcmd) && (!strcmp(fcmd, PERMIT_ALL_COMMANDS))){
if (get_next_token(&lp) == NULL){
- loc_fcmd =cmd ? strdup(cmd): NULL;
+ loc_fcmd =cmd ? xstrdup(cmd): NULL;
loc_found = TRUE;
}
free (line);
char * lp, * tc;
int i=0;
- tmp_fcmd = (char **) calloc (MAX_CMD, sizeof(char *));
+ tmp_fcmd = (char **) xcalloc (MAX_CMD, sizeof(char *));
if (*fcmd == '/'){ /* must be full path */
- tmp_fcmd[0] = strdup(fcmd);
+ tmp_fcmd[0] = xstrdup(fcmd);
tmp_fcmd[1] = NULL;
*out_fcmd = tmp_fcmd;
return TRUE;
}else{
/* must be either full path or just the cmd name */
if (strchr(fcmd, '/')){
- err = (char *) calloc((strlen(fcmd) +200) ,sizeof(char));
+ err = (char *) xcalloc((strlen(fcmd) +200) ,sizeof(char));
sprintf(err,"Error: bad entry - %s in %s file, must be either full path or just the cmd name\n", fcmd, KRB5_USERS_NAME);
*out_err = err;
return FALSE;
}
#ifndef CMD_PATH
- err = (char *) calloc(2*(strlen(fcmd) +200) ,sizeof(char));
+ err = (char *) xcalloc(2*(strlen(fcmd) +200) ,sizeof(char));
sprintf(err,"Error: bad entry - %s in %s file, since %s is just the cmd name, CMD_PATH must be defined \n", fcmd, KRB5_USERS_NAME, fcmd);
*out_err = err;
return FALSE;
#else
- path = strdup (CMD_PATH);
+ path = xstrdup (CMD_PATH);
path_ptr = path;
while ((*path_ptr == ' ') || (*path_ptr == '\t')) path_ptr ++;
tc = get_first_token (path_ptr, &lp);
if (! tc){
- err = (char *) calloc((strlen(fcmd) +200) ,sizeof(char));
+ err = (char *) xcalloc((strlen(fcmd) +200) ,sizeof(char));
sprintf(err,"Error: bad entry - %s in %s file, CMD_PATH contains no paths \n", fcmd, KRB5_USERS_NAME);
*out_err = err;
return FALSE;
i=0;
do{
if (*tc != '/'){ /* must be full path */
- err = (char *) calloc((strlen(tc) +200) ,sizeof(char));
+ err = (char *) xcalloc((strlen(tc) +200) ,sizeof(char));
sprintf(err,"Error: bad path %s in CMD_PATH for %s must start with '/' \n",tc, KRB5_USERS_NAME );
*out_err = err;
return FALSE;
}
- out_path = (char *) calloc( MAXPATHLEN, sizeof (char));
+ out_path = (char *) xmalloc(strlen(tc) + strlen(fcmd) + 2);
sprintf(out_path,"%s/%s",tc, fcmd );
tmp_fcmd[i] = out_path;
tln = strlen(fcmd_arr[i]);
if ( tln > max_ln) max_ln = tln;
if (!stat (fcmd_arr[i], &st_temp )){
- *cmd_out = strdup(fcmd_arr[i]);
+ *cmd_out = xstrdup(fcmd_arr[i]);
retbool = TRUE;
break;
}
}
if (retbool == FALSE ){
- err = (char *) calloc((80 +max_ln*i) ,sizeof(char));
- sprintf(err,"Error: not found -> ");
+ err = (char *) xmalloc((80 + (max_ln+2)*i) ,sizeof(char));
+ strcpy(err,"Error: not found -> ");
for(j= 0; j < i; j ++){
- sprintf(err,"%s %s ", err, fcmd_arr[j]);
+ strcat(err, " ");
+ strcat(err, fcmd_arr[j]);
+ strcat(err, " ");
}
- sprintf(err,"%s\n", err);
+ strcat(err, "\n");
*err_out = err;
}
}else{
if (!cmd_arr_cmp(fcmd_arr, cmd)){ /* found */
*match = TRUE;
- *cmd_out = strdup(cmd);
+ *cmd_out = xstrdup(cmd);
return 0;
} else{
*match = FALSE;
char * line, *r, *newline , *line_ptr;
int chunk_count = 1;
- line = (char *) calloc (BUFSIZ, sizeof (char ));
+ line = (char *) xcalloc (BUFSIZ, sizeof (char ));
line_ptr = line;
line[0] = '\0';
return out_ptr;
}
-static void auth_cleanup(k5users_flag, users_fp, k5login_flag,
- login_fp, princname)
- int k5users_flag;
+static void auth_cleanup(users_fp, login_fp, princname)
FILE *users_fp;
- int k5login_flag;
FILE *login_fp;
char *princname;
{
free (princname);
- if (!k5users_flag) fclose(users_fp);
- if (!k5login_flag) fclose(login_fp);
+ if (users_fp)
+ fclose(users_fp);
+ if (login_fp)
+ fclose(login_fp);
}
void init_auth_names(pw_dir)
char *pw_dir;
{
+ if (strlen (k5login_path) + 2 + strlen (KRB5_LOGIN_NAME) >= MAXPATHLEN) {
+ fprintf (stderr,
+ "home directory name `%s' too long, can't search for .k5login\n",
+ pw_dir);
+ exit (1);
+ }
if ((strlen(pw_dir) == 1) && (*pw_dir == '/')){
sprintf(k5login_path,"%s%s", pw_dir, KRB5_LOGIN_NAME);
sprintf(k5users_path,"%s%s", pw_dir, KRB5_USERS_NAME);
- }else{
+ } else {
sprintf(k5login_path,"%s/%s", pw_dir, KRB5_LOGIN_NAME);
sprintf(k5users_path,"%s/%s", pw_dir, KRB5_USERS_NAME);
}
krb5_creds ** cc_other_creds_arr = NULL;
struct stat st_temp;
- cc_other = (krb5_ccache *) calloc(1, sizeof (krb5_ccache));
+ cc_other = (krb5_ccache *) xcalloc(1, sizeof (krb5_ccache));
if ((retval = krb5_cc_resolve(context, cc_other_tag, cc_other))){
com_err (prog_name, retval, "resolving ccache %s",
if ((pwd = getpwnam(luser)) == NULL) {
return 0;
}
+ if (strlen(pwd->pw_dir) + sizeof("/.k5login") > MAXPATHLEN) {
+ fprintf (stderr, "home directory path for %s too long\n", luser);
+ exit (1);
+ }
(void) strcpy(pbuf, pwd->pw_dir);
(void) strcat(pbuf, "/.k5login");
krb5_creds ** cc_other_creds_arr = NULL;
struct stat st_temp;
- cc_other = (krb5_ccache *) calloc(1, sizeof (krb5_ccache));
+ cc_other = (krb5_ccache *) xcalloc(1, sizeof (krb5_ccache));
if ((retval = krb5_cc_resolve(context, cc_other_tag, cc_other))){
com_err (prog_name, retval, "resolving ccache %s",
if ( ! stat(cc_name, &st_temp)){
if (auth_debug) {
- fprintf(stderr,"puting cache %s through a filter for -z option\n", cc_name);
+ fprintf(stderr,"putting cache %s through a filter for -z option\n", cc_name);
}
if ((retval = krb5_get_nonexp_tkts(context, cc, &cc_creds_arr))){
fprinc = get_first_token (line, &lp);
if (fprinc ){
- temp_list[count] = strdup(fprinc);
+ temp_list[count] = xstrdup(fprinc);
count ++;
}
} else
my_creds.times.renew_till = 0;
-
- (void) sprintf(prompt,"Kerberos password for %s: ", (char *) client_name);
+ if (strlen (client_name) + 80 > sizeof (prompt)) {
+ fprintf (stderr,
+ "principal name %s too long for internal buffer space\n",
+ client_name);
+ return FALSE;
+ }
+ (void) sprintf(prompt,"Kerberos password for %s: ", client_name);
pwsize = sizeof(password);
krb5_context context;
char *str;
krb5_principal p;
-{
-char * stname;
-krb5_error_code retval;
+{
+ char * stname;
+ krb5_error_code retval;
- if ((retval = krb5_unparse_name(context, p, &stname))){
- fprintf(stderr," %s while unparsing name \n",
- error_message(retval));
- }
- fprintf(stderr, " %s: %s\n", str, stname );
+ if ((retval = krb5_unparse_name(context, p, &stname))) {
+ fprintf(stderr, " %s while unparsing name\n", error_message(retval));
+ }
+ fprintf(stderr, " %s: %s\n", str, stname);
}
void plain_dump_principal (context, p)
krb5_context context;
krb5_principal p;
{
-char * stname;
-krb5_error_code retval;
+ char * stname;
+ krb5_error_code retval;
- if ((retval = krb5_unparse_name(context, p, &stname))){
- fprintf(stderr," %s while unparsing name \n",
- error_message(retval));
- }
- fprintf(stderr, "%s ", stname );
+ if ((retval = krb5_unparse_name(context, p, &stname)))
+ fprintf(stderr, " %s while unparsing name\n", error_message(retval));
+ fprintf(stderr, "%s ", stname);
}
#if 0
extern krb5_error_code get_params PROTOTYPE((int *, int, char **, char ***));
-extern char *get_dir_of_file PROTOTYPE((char *));
+extern char *get_dir_of_file PROTOTYPE((const char *));
/* heuristic.c */
extern krb5_error_code get_all_princ_from_file PROTOTYPE((FILE *, char ***));
extern char *krb5_lname_file; /* Note: print this out just be sure
that it gets set */
-
+extern void *xmalloc (), *xrealloc (), *xcalloc();
+extern char *xstrdup ();
char * source_user;
krb5_ccache cc_source = NULL;
-char * cc_source_tag = NULL;
+const char * cc_source_tag = NULL;
uid_t source_gid, target_gid;
-char * cc_source_tag_tmp = NULL;
+const char * cc_source_tag_tmp = NULL;
char * cc_target_tag_tmp=NULL;
char * cmd = NULL, * exec_cmd = NULL;
int errflg = 0;
options.rlife =0;
options.princ =0;
- params = (char **) calloc (2, sizeof (char *));
+ params = (char **) xcalloc (2, sizeof (char *));
params[1] = NULL;
- retval = krb5_init_context(&ksu_context);
+ unsetenv ("KRB5_CONFIG");
+
+ retval = krb5_init_secure_context(&ksu_context);
if (retval) {
com_err(argv[0], retval, "while initializing krb5");
exit(1);
}
- krb5_secure_config_files(ksu_context);
if (strrchr(argv[0], '/'))
argv[0] = strrchr(argv[0], '/')+1;
if (( argc == 1) || (argv[1][0] == '-')){
- target_user = strdup("root");
+ target_user = xstrdup("root");
pargc = argc;
pargv = argv;
} else {
- target_user = strdup(argv[1]);
+ target_user = xstrdup(argv[1]);
pargc = argc -1;
if ((pargv =(char **) calloc(pargc +1,sizeof(char *)))==NULL){
}
- while(!done && ((option = getopt(pargc, pargv,"n:c:C:r:a:zZDfpkql:e:")) != -1)){
+ while(!done && ((option = getopt(pargc, pargv,"n:c:r:a:zZDfpkql:e:")) != -1)){
switch (option) {
case 'r':
options.opt |= KDC_OPT_RENEWABLE;
+ if (strlen (optarg) >= 14)
+ optarg = "bad-time";
retval = krb5_string_to_deltat(optarg, &options.rlife);
if (retval != 0 || options.rlife == 0) {
fprintf(stderr, "Bad lifetime value (%s hours?)\n", optarg);
quiet =1;
break;
case 'l':
+ if (strlen (optarg) >= 14)
+ optarg = "bad-time";
retval = krb5_string_to_deltat(optarg, &options.lifetime);
if (retval != 0 || options.lifetime == 0) {
fprintf(stderr, "Bad lifetime value (%s hours?)\n", optarg);
errflg++;
}
break;
- case 'C':
- if (cc_target_tag == NULL) {
- cc_target_tag = strdup(optarg);
-
- if ((strlen(cc_target_tag) == 1) &&
- (*cc_target_tag == NO_TARGET_FILE)){
- use_source_cache = 1;
- if(some_rest_copy || all_rest_copy){
- fprintf(stderr,
- "-C . option is mutually exclusive with -z and -Z\n");
- errflg++;
- }
- }
- else {
- if ( strchr(cc_target_tag, ':')){
- cc_target_tag_tmp=strchr(cc_target_tag,':') + 1;
- if(!stat(cc_target_tag_tmp, &st_temp )){
- fprintf(stderr,"File %s exists\n",
- cc_target_tag_tmp);
- errflg++;
- }
- }
- else {
- fprintf(stderr,
- "malformed credential cache name %s\n",
- cc_target_tag);
- errflg++;
- }
- }
- } else {
- fprintf(stderr, "Only one -C option allowed\n");
- errflg++;
- }
- break;
case 'c':
if (cc_source_tag == NULL) {
- cc_source_tag = strdup(optarg);
+ cc_source_tag = xstrdup(optarg);
if ( strchr(cc_source_tag, ':')){
cc_source_tag_tmp = strchr(cc_source_tag, ':') + 1;
}
break;
case 'e':
- cmd = strdup(optarg);
+ cmd = xstrdup(optarg);
if(auth_debug){printf("Before get_params optind=%d\n", optind);}
if ((retval = get_params( & optind, pargc, pargv, ¶ms))){
com_err(prog_name, retval, "when gathering parameters");
}
/* allocate space and copy the usernamane there */
- source_user = strdup(pwd->pw_name);
+ source_user = xstrdup(pwd->pw_name);
source_uid = pwd->pw_uid;
source_gid = pwd->pw_gid;
if (!strcmp(SOURCE_USER_LOGIN, target_user)){
- target_user = strdup (source_user);
+ target_user = xstrdup (source_user);
}
if ((target_pwd = getpwnam(target_user)) == NULL){
if (cc_source_tag == NULL){
cc_source_tag = krb5_cc_default_name(ksu_context);
- cc_source_tag_tmp = strchr(cc_source_tag, ':') + 1;
- if (cc_source_tag_tmp == (char *) 1)
+ cc_source_tag_tmp = strchr(cc_source_tag, ':');
+ if (cc_source_tag_tmp == 0)
cc_source_tag_tmp = cc_source_tag;
+ else
+ cc_source_tag_tmp++;
}
if (krb5_seteuid(source_uid)) {
com_err ( prog_name, errno, "while setting euid to source user");
if (cc_target_tag == NULL) {
- cc_target_tag = (char *)calloc(KRB5_SEC_BUFFSIZE ,sizeof(char));
+ cc_target_tag = (char *)xcalloc(KRB5_SEC_BUFFSIZE ,sizeof(char));
/* make sure that the new ticket file does not already exist
This is run as source_uid because it is reasonable to
require the source user to have write to where the target
cache will be created.*/
do {
- sprintf(cc_target_tag, "%s%d.%d", KRB5_SECONDARY_CACHE,
- target_uid, gen_sym());
+ sprintf(cc_target_tag, "%s%ld.%d",
+ KRB5_SECONDARY_CACHE,
+ (long) target_uid, gen_sym());
cc_target_tag_tmp = strchr(cc_target_tag, ':') + 1;
}while ( !stat ( cc_target_tag_tmp, &st_temp));
}
else{
cc_target = cc_source;
- cc_target_tag = cc_source_tag;
- cc_target_tag_tmp = cc_source_tag_tmp;
+ cc_target_tag = (char *) cc_source_tag;
+ cc_target_tag_tmp = (char *) cc_source_tag_tmp;
if ((retval=krb5_find_princ_in_cache(ksu_context, cc_target,client, &stored))){
com_err (prog_name, retval,
/* Run authorization as target.*/
if (krb5_seteuid(target_uid)) {
- com_err(prog_name, errno, "whiel switching to target for authorization check");
+ com_err(prog_name, errno, "while switching to target for authorization check");
sweep_up(ksu_context, use_source_cache, cc_target);
exit(1);
}
target_pwd = getpwnam(target_user);
if (target_pwd->pw_shell)
- shell = strdup(target_pwd->pw_shell);
+ shell = xstrdup(target_pwd->pw_shell);
else {
shell = _DEF_CSH; /* default is cshell */
}
* with C2 enabled.
*/
if (setluid((uid_t) pwd->pw_uid) < 0) {
- perror("setuid");
+ perror("setluid");
sweep_up(ksu_context, use_source_cache, cc_target);
exit(1);
}
switch ((child_pid = fork())) {
default:
if (auth_debug){
- printf(" The child pid is %d\n", child_pid);
+ printf(" The child pid is %ld\n", (long) child_pid);
printf(" The parent pid is %d\n", getpid());
}
while ((ret_pid = waitpid(child_pid, &statusp, WUNTRACED)) != -1) {
static char buf[MAXPATHLEN + 4];
buf[0] = 0;
- if ((p = ttyname(STDERR_FILENO)))
+ if ((p = ttyname(STDERR_FILENO))) {
+ if (strlen (p) > MAXPATHLEN) {
+ fprintf (stderr, "terminal name %s too long\n", p);
+ exit (1);
+ }
sprintf(buf, " on %s", p);
+ }
return (buf);
}
char * env_var_buf;
/* allocate extra two spaces, one for the = and one for the \0 */
- env_var_buf = (char *) calloc(2 + strlen(name) + strlen(value),
+ env_var_buf = (char *) xcalloc(2 + strlen(name) + strlen(value),
sizeof(char));
sprintf(env_var_buf,"%s=%s",name, value);
char *get_dir_of_file(path)
- char *path;
+ const char *path;
{
char * temp_path;
char * ptr;
- temp_path = strdup(path);
+ temp_path = xstrdup(path);
if ((ptr = strrchr( temp_path, '/'))) {
*ptr = '\0';
} else {
free (temp_path);
- temp_path = malloc(MAXPATHLEN);
+ temp_path = xmalloc(MAXPATHLEN);
if (temp_path)
getcwd(temp_path, MAXPATHLEN);
}
--- /dev/null
+/*
+ * Copyright (c) 1987 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* based on @(#)setenv.c 5.2 (Berkeley) 6/27/88 */
+
+#include <sys/types.h>
+#include <stdio.h>
+
+/*
+ * setenv --
+ * Set the value of the environmental variable "name" to be
+ * "value". If rewrite is set, replace any current value.
+ */
+setenv(name, value, rewrite)
+ register char *name, *value;
+ int rewrite;
+{
+ extern char **environ;
+ static int alloced; /* if allocated space before */
+ register char *C;
+ int l_value, offset;
+ char *malloc(), *realloc(), *_findenv();
+
+ if (*value == '=') /* no `=' in value */
+ ++value;
+ l_value = strlen(value);
+ if ((C = _findenv(name, &offset))) { /* find if already exists */
+ if (!rewrite)
+ return(0);
+ if (strlen(C) >= l_value) { /* old larger; copy over */
+ while (*C++ = *value++);
+ return(0);
+ }
+ }
+ else { /* create new slot */
+ register int cnt;
+ register char **P;
+
+ for (P = environ, cnt = 0; *P; ++P, ++cnt);
+ if (alloced) { /* just increase size */
+ environ = (char **)realloc((char *)environ,
+ (u_int)(sizeof(char *) * (cnt + 2)));
+ if (!environ)
+ return(-1);
+ }
+ else { /* get new space */
+ alloced = 1; /* copy old entries into it */
+ P = (char **)malloc((u_int)(sizeof(char *) *
+ (cnt + 2)));
+ if (!P)
+ return(-1);
+ memcpy(P, environ, cnt * sizeof(char *));
+ environ = P;
+ }
+ environ[cnt + 1] = NULL;
+ offset = cnt;
+ }
+ for (C = name; *C && *C != '='; ++C); /* no `=' in name */
+ if (!(environ[offset] = /* name + `=' + value */
+ malloc((u_int)((int)(C - name) + l_value + 2))))
+ return(-1);
+ for (C = environ[offset]; (*C = *name++) &&( *C != '='); ++C);
+ for (*C++ = '='; *C++ = *value++;);
+ return(0);
+}
+
+/*
+ * unsetenv(name) --
+ * Delete environmental variable "name".
+ */
+void
+unsetenv(name)
+ char *name;
+{
+ extern char **environ;
+ register char **P;
+ int offset;
+ char *_findenv();
+
+ while (_findenv(name, &offset)) /* if set multiple times */
+ for (P = &environ[offset];; ++P)
+ if (!(*P = *(P + 1)))
+ break;
+}
+/*
+ * Copyright (c) 1987 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* based on @(#)getenv.c 5.5 (Berkeley) 6/27/88 */
+
+/*
+ * getenv --
+ * Returns ptr to value associated with name, if any, else NULL.
+ */
+char *
+getenv(name)
+ char *name;
+{
+ int offset;
+ char *_findenv();
+
+ return(_findenv(name, &offset));
+}
+
+/*
+ * _findenv --
+ * Returns pointer to value associated with name, if any, else NULL.
+ * Sets offset to be the offset of the name/value combination in the
+ * environmental array, for use by setenv(3) and unsetenv(3).
+ * Explicitly removes '=' in argument name.
+ *
+ * This routine *should* be a static; don't use it.
+ */
+char *
+_findenv(name, offset)
+ register char *name;
+ int *offset;
+{
+ extern char **environ;
+ register int len;
+ register char **P, *C;
+
+ for (C = name, len = 0; *C && *C != '='; ++C, ++len);
+ for (P = environ; *P; ++P)
+ if (!strncmp(*P, name, len))
+ if (*(C = *P + len) == '=') {
+ *offset = P - environ;
+ return(++C);
+ }
+ return(NULL);
+}
--- /dev/null
+/*
+ * clients/ksu/xmalloc.c
+ *
+ * Copyright 1999 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ *
+ * Perform simple allocation/copy operations, exiting on failure.
+ */
+
+#include "ksu.h"
+
+void *xmalloc (size_t sz)
+{
+ void *ret = malloc (sz);
+ if (ret == 0 && sz != 0) {
+ perror (prog_name);
+ exit (1);
+ }
+ return ret;
+}
+
+void *xrealloc (void *old, size_t newsz)
+{
+ void *ret = realloc (old, newsz);
+ if (ret == 0 && newsz != 0) {
+ perror (prog_name);
+ exit (1);
+ }
+ return ret;
+}
+
+void *xcalloc (size_t nelts, size_t eltsz)
+{
+ void *ret = calloc (nelts, eltsz);
+ if (ret == 0 && nelts != 0 && eltsz != 0) {
+ perror (prog_name);
+ exit (1);
+ }
+ return ret;
+}
+
+char *xstrdup (const char *src)
+{
+ size_t len = strlen (src) + 1;
+ char *dst = xmalloc (len);
+ memcpy (dst, src, len);
+ return dst;
+}