rlogind.c revision 2076
1/*- 2 * Copyright (c) 1983, 1988, 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#ifndef lint 35static char copyright[] = 36"@(#) Copyright (c) 1983, 1988, 1989, 1993\n\ 37 The Regents of the University of California. All rights reserved.\n"; 38#endif /* not lint */ 39 40#ifndef lint 41static char sccsid[] = "@(#)rlogind.c 8.1 (Berkeley) 6/4/93"; 42#endif /* not lint */ 43 44/* 45 * remote login server: 46 * \0 47 * remuser\0 48 * locuser\0 49 * terminal_type/speed\0 50 * data 51 */ 52 53#define FD_SETSIZE 16 /* don't need many bits for select */ 54#include <sys/param.h> 55#include <sys/stat.h> 56#include <sys/ioctl.h> 57#include <signal.h> 58#include <termios.h> 59 60#include <sys/socket.h> 61#include <netinet/in.h> 62#include <netinet/in_systm.h> 63#include <netinet/ip.h> 64#include <arpa/inet.h> 65#include <netdb.h> 66 67#include <pwd.h> 68#include <syslog.h> 69#include <errno.h> 70#include <stdio.h> 71#include <unistd.h> 72#include <stdlib.h> 73#include <string.h> 74#include "pathnames.h" 75 76#ifndef TIOCPKT_WINDOW 77#define TIOCPKT_WINDOW 0x80 78#endif 79 80#ifdef KERBEROS 81#include <kerberosIV/des.h> 82#include <kerberosIV/krb.h> 83#define SECURE_MESSAGE "This rlogin session is using DES encryption for all transmissions.\r\n" 84 85AUTH_DAT *kdata; 86KTEXT ticket; 87u_char auth_buf[sizeof(AUTH_DAT)]; 88u_char tick_buf[sizeof(KTEXT_ST)]; 89Key_schedule schedule; 90int doencrypt, retval, use_kerberos, vacuous; 91 92#define ARGSTR "alnkvx" 93#else 94#define ARGSTR "aln" 95#endif /* KERBEROS */ 96 97char *env[2]; 98#define NMAX 30 99char lusername[NMAX+1], rusername[NMAX+1]; 100static char term[64] = "TERM="; 101#define ENVSIZE (sizeof("TERM=")-1) /* skip null for concatenation */ 102int keepalive = 1; 103int check_all = 0; 104 105struct passwd *pwd; 106 107void doit __P((int, struct sockaddr_in *)); 108int control __P((int, char *, int)); 109void protocol __P((int, int)); 110void cleanup __P((int)); 111void fatal __P((int, char *, int)); 112int do_rlogin __P((struct sockaddr_in *)); 113void getstr __P((char *, int, char *)); 114void setup_term __P((int)); 115int do_krb_login __P((struct sockaddr_in *)); 116void usage __P((void)); 117int local_domain __P((char *)); 118char *topdomain __P((char *)); 119 120int 121main(argc, argv) 122 int argc; 123 char *argv[]; 124{ 125 extern int __check_rhosts_file; 126 struct sockaddr_in from; 127 int ch, fromlen, on; 128 129 openlog("rlogind", LOG_PID | LOG_CONS, LOG_AUTH); 130 131 opterr = 0; 132 while ((ch = getopt(argc, argv, ARGSTR)) != EOF) 133 switch (ch) { 134 case 'a': 135 check_all = 1; 136 break; 137 case 'l': 138 __check_rhosts_file = 0; 139 break; 140 case 'n': 141 keepalive = 0; 142 break; 143#ifdef KERBEROS 144 case 'k': 145 use_kerberos = 1; 146 break; 147 case 'v': 148 vacuous = 1; 149 break; 150#ifdef CRYPT 151 case 'x': 152 doencrypt = 1; 153 break; 154#endif 155#endif 156 case '?': 157 default: 158 usage(); 159 break; 160 } 161 argc -= optind; 162 argv += optind; 163 164#ifdef KERBEROS 165 if (use_kerberos && vacuous) { 166 usage(); 167 fatal(STDERR_FILENO, "only one of -k and -v allowed", 0); 168 } 169#endif 170 fromlen = sizeof (from); 171 if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) { 172 syslog(LOG_ERR,"Can't get peer name of remote host: %m"); 173 fatal(STDERR_FILENO, "Can't get peer name of remote host", 1); 174 } 175 on = 1; 176 if (keepalive && 177 setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) 178 syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 179 on = IPTOS_LOWDELAY; 180 if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0) 181 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); 182 doit(0, &from); 183} 184 185int child; 186int netf; 187char line[MAXPATHLEN]; 188int confirmed; 189 190struct winsize win = { 0, 0, 0, 0 }; 191 192 193void 194doit(f, fromp) 195 int f; 196 struct sockaddr_in *fromp; 197{ 198 int master, pid, on = 1; 199 int authenticated = 0; 200 register struct hostent *hp; 201 char hostname[2 * MAXHOSTNAMELEN + 1]; 202 char c; 203 204 alarm(60); 205 read(f, &c, 1); 206 207 if (c != 0) 208 exit(1); 209#ifdef KERBEROS 210 if (vacuous) 211 fatal(f, "Remote host requires Kerberos authentication", 0); 212#endif 213 214 alarm(0); 215 fromp->sin_port = ntohs((u_short)fromp->sin_port); 216 hp = gethostbyaddr((char *)&fromp->sin_addr, sizeof(struct in_addr), 217 fromp->sin_family); 218 if (hp) 219 (void)strcpy(hostname, hp->h_name); 220 else 221 (void)strcpy(hostname, inet_ntoa(fromp->sin_addr)); 222 223#ifdef KERBEROS 224 if (use_kerberos) { 225 retval = do_krb_login(fromp); 226 if (retval == 0) 227 authenticated++; 228 else if (retval > 0) 229 fatal(f, krb_err_txt[retval], 0); 230 write(f, &c, 1); 231 confirmed = 1; /* we sent the null! */ 232 } else 233#endif 234 { 235 if (fromp->sin_family != AF_INET || 236 fromp->sin_port >= IPPORT_RESERVED || 237 fromp->sin_port < IPPORT_RESERVED/2) { 238 syslog(LOG_NOTICE, "Connection from %s on illegal port", 239 inet_ntoa(fromp->sin_addr)); 240 fatal(f, "Permission denied", 0); 241 } 242#ifdef IP_OPTIONS 243 { 244 u_char optbuf[BUFSIZ/3], *cp; 245 char lbuf[BUFSIZ], *lp; 246 int optsize = sizeof(optbuf), ipproto; 247 struct protoent *ip; 248 249 if ((ip = getprotobyname("ip")) != NULL) 250 ipproto = ip->p_proto; 251 else 252 ipproto = IPPROTO_IP; 253 if (getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, 254 &optsize) == 0 && optsize != 0) { 255 lp = lbuf; 256 for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3) 257 sprintf(lp, " %2.2x", *cp); 258 syslog(LOG_NOTICE, 259 "Connection received using IP options (ignored):%s", 260 lbuf); 261 if (setsockopt(0, ipproto, IP_OPTIONS, 262 (char *)NULL, optsize) != 0) { 263 syslog(LOG_ERR, 264 "setsockopt IP_OPTIONS NULL: %m"); 265 exit(1); 266 } 267 } 268 } 269#endif 270 if (do_rlogin(fromp) == 0) 271 authenticated++; 272 } 273 if (confirmed == 0) { 274 write(f, "", 1); 275 confirmed = 1; /* we sent the null! */ 276 } 277#ifdef KERBEROS 278#ifdef CRYPT 279 if (doencrypt) 280 (void) des_write(f, SECURE_MESSAGE, sizeof(SECURE_MESSAGE) - 1); 281#endif 282#endif 283 netf = f; 284 285 pid = forkpty(&master, line, NULL, &win); 286 if (pid < 0) { 287 if (errno == ENOENT) 288 fatal(f, "Out of ptys", 0); 289 else 290 fatal(f, "Forkpty", 1); 291 } 292 if (pid == 0) { 293 if (f > 2) /* f should always be 0, but... */ 294 (void) close(f); 295 setup_term(0); 296 if (strchr(lusername, '-')) { 297 syslog(LOG_ERR, "tried to pass user \"%s\" to login", 298 lusername); 299 fatal(STDERR_FILENO, "invalid user", 0); 300 } 301 if (authenticated) { 302#ifdef KERBEROS 303 if (use_kerberos && (pwd->pw_uid == 0)) 304 syslog(LOG_INFO|LOG_AUTH, 305 "ROOT Kerberos login from %s.%s@%s on %s\n", 306 kdata->pname, kdata->pinst, kdata->prealm, 307 hostname); 308#endif 309 310 execl(_PATH_LOGIN, "login", "-p", 311 "-h", hostname, "-f", lusername, (char *)NULL); 312 } else 313 execl(_PATH_LOGIN, "login", "-p", 314 "-h", hostname, lusername, (char *)NULL); 315 fatal(STDERR_FILENO, _PATH_LOGIN, 1); 316 /*NOTREACHED*/ 317 } 318#ifdef CRYPT 319#ifdef KERBEROS 320 /* 321 * If encrypted, don't turn on NBIO or the des read/write 322 * routines will croak. 323 */ 324 325 if (!doencrypt) 326#endif 327#endif 328 ioctl(f, FIONBIO, &on); 329 ioctl(master, FIONBIO, &on); 330 ioctl(master, TIOCPKT, &on); 331 signal(SIGCHLD, cleanup); 332 protocol(f, master); 333 signal(SIGCHLD, SIG_IGN); 334 cleanup(0); 335} 336 337char magic[2] = { 0377, 0377 }; 338char oobdata[] = {TIOCPKT_WINDOW}; 339 340/* 341 * Handle a "control" request (signaled by magic being present) 342 * in the data stream. For now, we are only willing to handle 343 * window size changes. 344 */ 345int 346control(pty, cp, n) 347 int pty; 348 char *cp; 349 int n; 350{ 351 struct winsize w; 352 353 if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's') 354 return (0); 355 oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */ 356 bcopy(cp+4, (char *)&w, sizeof(w)); 357 w.ws_row = ntohs(w.ws_row); 358 w.ws_col = ntohs(w.ws_col); 359 w.ws_xpixel = ntohs(w.ws_xpixel); 360 w.ws_ypixel = ntohs(w.ws_ypixel); 361 (void)ioctl(pty, TIOCSWINSZ, &w); 362 return (4+sizeof (w)); 363} 364 365/* 366 * rlogin "protocol" machine. 367 */ 368void 369protocol(f, p) 370 register int f, p; 371{ 372 char pibuf[1024+1], fibuf[1024], *pbp, *fbp; 373 register pcc = 0, fcc = 0; 374 int cc, nfd, n; 375 char cntl; 376 377 /* 378 * Must ignore SIGTTOU, otherwise we'll stop 379 * when we try and set slave pty's window shape 380 * (our controlling tty is the master pty). 381 */ 382 (void) signal(SIGTTOU, SIG_IGN); 383 send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */ 384 if (f > p) 385 nfd = f + 1; 386 else 387 nfd = p + 1; 388 if (nfd > FD_SETSIZE) { 389 syslog(LOG_ERR, "select mask too small, increase FD_SETSIZE"); 390 fatal(f, "internal error (select mask too small)", 0); 391 } 392 for (;;) { 393 fd_set ibits, obits, ebits, *omask; 394 395 FD_ZERO(&ebits); 396 FD_ZERO(&ibits); 397 FD_ZERO(&obits); 398 omask = (fd_set *)NULL; 399 if (fcc) { 400 FD_SET(p, &obits); 401 omask = &obits; 402 } else 403 FD_SET(f, &ibits); 404 if (pcc >= 0) 405 if (pcc) { 406 FD_SET(f, &obits); 407 omask = &obits; 408 } else 409 FD_SET(p, &ibits); 410 FD_SET(p, &ebits); 411 if ((n = select(nfd, &ibits, omask, &ebits, 0)) < 0) { 412 if (errno == EINTR) 413 continue; 414 fatal(f, "select", 1); 415 } 416 if (n == 0) { 417 /* shouldn't happen... */ 418 sleep(5); 419 continue; 420 } 421#define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP)) 422 if (FD_ISSET(p, &ebits)) { 423 cc = read(p, &cntl, 1); 424 if (cc == 1 && pkcontrol(cntl)) { 425 cntl |= oobdata[0]; 426 send(f, &cntl, 1, MSG_OOB); 427 if (cntl & TIOCPKT_FLUSHWRITE) { 428 pcc = 0; 429 FD_CLR(p, &ibits); 430 } 431 } 432 } 433 if (FD_ISSET(f, &ibits)) { 434#ifdef CRYPT 435#ifdef KERBEROS 436 if (doencrypt) 437 fcc = des_read(f, fibuf, sizeof(fibuf)); 438 else 439#endif 440#endif 441 fcc = read(f, fibuf, sizeof(fibuf)); 442 if (fcc < 0 && errno == EWOULDBLOCK) 443 fcc = 0; 444 else { 445 register char *cp; 446 int left, n; 447 448 if (fcc <= 0) 449 break; 450 fbp = fibuf; 451 452 top: 453 for (cp = fibuf; cp < fibuf+fcc-1; cp++) 454 if (cp[0] == magic[0] && 455 cp[1] == magic[1]) { 456 left = fcc - (cp-fibuf); 457 n = control(p, cp, left); 458 if (n) { 459 left -= n; 460 if (left > 0) 461 bcopy(cp+n, cp, left); 462 fcc -= n; 463 goto top; /* n^2 */ 464 } 465 } 466 FD_SET(p, &obits); /* try write */ 467 } 468 } 469 470 if (FD_ISSET(p, &obits) && fcc > 0) { 471 cc = write(p, fbp, fcc); 472 if (cc > 0) { 473 fcc -= cc; 474 fbp += cc; 475 } 476 } 477 478 if (FD_ISSET(p, &ibits)) { 479 pcc = read(p, pibuf, sizeof (pibuf)); 480 pbp = pibuf; 481 if (pcc < 0 && errno == EWOULDBLOCK) 482 pcc = 0; 483 else if (pcc <= 0) 484 break; 485 else if (pibuf[0] == 0) { 486 pbp++, pcc--; 487#ifdef CRYPT 488#ifdef KERBEROS 489 if (!doencrypt) 490#endif 491#endif 492 FD_SET(f, &obits); /* try write */ 493 } else { 494 if (pkcontrol(pibuf[0])) { 495 pibuf[0] |= oobdata[0]; 496 send(f, &pibuf[0], 1, MSG_OOB); 497 } 498 pcc = 0; 499 } 500 } 501 if ((FD_ISSET(f, &obits)) && pcc > 0) { 502#ifdef CRYPT 503#ifdef KERBEROS 504 if (doencrypt) 505 cc = des_write(f, pbp, pcc); 506 else 507#endif 508#endif 509 cc = write(f, pbp, pcc); 510 if (cc < 0 && errno == EWOULDBLOCK) { 511 /* 512 * This happens when we try write after read 513 * from p, but some old kernels balk at large 514 * writes even when select returns true. 515 */ 516 if (!FD_ISSET(p, &ibits)) 517 sleep(5); 518 continue; 519 } 520 if (cc > 0) { 521 pcc -= cc; 522 pbp += cc; 523 } 524 } 525 } 526} 527 528void 529cleanup(signo) 530 int signo; 531{ 532 char *p; 533 534 p = line + sizeof(_PATH_DEV) - 1; 535 if (logout(p)) 536 logwtmp(p, "", ""); 537 (void)chmod(line, 0666); 538 (void)chown(line, 0, 0); 539 *p = 'p'; 540 (void)chmod(line, 0666); 541 (void)chown(line, 0, 0); 542 shutdown(netf, 2); 543 exit(1); 544} 545 546void 547fatal(f, msg, syserr) 548 int f; 549 char *msg; 550 int syserr; 551{ 552 int len; 553 char buf[BUFSIZ], *bp = buf; 554 555 /* 556 * Prepend binary one to message if we haven't sent 557 * the magic null as confirmation. 558 */ 559 if (!confirmed) 560 *bp++ = '\01'; /* error indicator */ 561 if (syserr) 562 len = sprintf(bp, "rlogind: %s: %s.\r\n", 563 msg, strerror(errno)); 564 else 565 len = sprintf(bp, "rlogind: %s.\r\n", msg); 566 (void) write(f, buf, bp + len - buf); 567 exit(1); 568} 569 570int 571do_rlogin(dest) 572 struct sockaddr_in *dest; 573{ 574 getstr(rusername, sizeof(rusername), "remuser too long"); 575 getstr(lusername, sizeof(lusername), "locuser too long"); 576 getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type too long"); 577 578 pwd = getpwnam(lusername); 579 if (pwd == NULL) 580 return (-1); 581 if (pwd->pw_uid == 0) 582 return (-1); 583 /* XXX why don't we syslog() failure? */ 584 return (iruserok(dest->sin_addr.s_addr, 0, rusername, lusername)); 585} 586 587void 588getstr(buf, cnt, errmsg) 589 char *buf; 590 int cnt; 591 char *errmsg; 592{ 593 char c; 594 595 do { 596 if (read(0, &c, 1) != 1) 597 exit(1); 598 if (--cnt < 0) 599 fatal(STDOUT_FILENO, errmsg, 0); 600 *buf++ = c; 601 } while (c != 0); 602} 603 604extern char **environ; 605 606void 607setup_term(fd) 608 int fd; 609{ 610 register char *cp = index(term+ENVSIZE, '/'); 611 char *speed; 612 struct termios tt; 613 614#ifndef notyet 615 tcgetattr(fd, &tt); 616 if (cp) { 617 *cp++ = '\0'; 618 speed = cp; 619 cp = index(speed, '/'); 620 if (cp) 621 *cp++ = '\0'; 622 cfsetspeed(&tt, atoi(speed)); 623 } 624 625 tt.c_iflag = TTYDEF_IFLAG; 626 tt.c_oflag = TTYDEF_OFLAG; 627 tt.c_lflag = TTYDEF_LFLAG; 628 tcsetattr(fd, TCSAFLUSH, &tt); 629#else 630 if (cp) { 631 *cp++ = '\0'; 632 speed = cp; 633 cp = index(speed, '/'); 634 if (cp) 635 *cp++ = '\0'; 636 tcgetattr(fd, &tt); 637 cfsetspeed(&tt, atoi(speed)); 638 tcsetattr(fd, TCSAFLUSH, &tt); 639 } 640#endif 641 642 env[0] = term; 643 env[1] = 0; 644 environ = env; 645} 646 647#ifdef KERBEROS 648#define VERSION_SIZE 9 649 650/* 651 * Do the remote kerberos login to the named host with the 652 * given inet address 653 * 654 * Return 0 on valid authorization 655 * Return -1 on valid authentication, no authorization 656 * Return >0 for error conditions 657 */ 658int 659do_krb_login(dest) 660 struct sockaddr_in *dest; 661{ 662 int rc; 663 char instance[INST_SZ], version[VERSION_SIZE]; 664 long authopts = 0L; /* !mutual */ 665 struct sockaddr_in faddr; 666 667 kdata = (AUTH_DAT *) auth_buf; 668 ticket = (KTEXT) tick_buf; 669 670 instance[0] = '*'; 671 instance[1] = '\0'; 672 673#ifdef CRYPT 674 if (doencrypt) { 675 rc = sizeof(faddr); 676 if (getsockname(0, (struct sockaddr *)&faddr, &rc)) 677 return (-1); 678 authopts = KOPT_DO_MUTUAL; 679 rc = krb_recvauth( 680 authopts, 0, 681 ticket, "rcmd", 682 instance, dest, &faddr, 683 kdata, "", schedule, version); 684 des_set_key(kdata->session, schedule); 685 686 } else 687#endif 688 rc = krb_recvauth( 689 authopts, 0, 690 ticket, "rcmd", 691 instance, dest, (struct sockaddr_in *) 0, 692 kdata, "", (bit_64 *) 0, version); 693 694 if (rc != KSUCCESS) 695 return (rc); 696 697 getstr(lusername, sizeof(lusername), "locuser"); 698 /* get the "cmd" in the rcmd protocol */ 699 getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type"); 700 701 pwd = getpwnam(lusername); 702 if (pwd == NULL) 703 return (-1); 704 705 /* returns nonzero for no access */ 706 if (kuserok(kdata, lusername) != 0) 707 return (-1); 708 709 return (0); 710 711} 712#endif /* KERBEROS */ 713 714void 715usage() 716{ 717#ifdef KERBEROS 718 syslog(LOG_ERR, "usage: rlogind [-aln] [-k | -v]"); 719#else 720 syslog(LOG_ERR, "usage: rlogind [-aln]"); 721#endif 722} 723 724/* 725 * Check whether host h is in our local domain, 726 * defined as sharing the last two components of the domain part, 727 * or the entire domain part if the local domain has only one component. 728 * If either name is unqualified (contains no '.'), 729 * assume that the host is local, as it will be 730 * interpreted as such. 731 */ 732int 733local_domain(h) 734 char *h; 735{ 736 char localhost[MAXHOSTNAMELEN]; 737 char *p1, *p2; 738 739 localhost[0] = 0; 740 (void) gethostname(localhost, sizeof(localhost)); 741 p1 = topdomain(localhost); 742 p2 = topdomain(h); 743 if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2)) 744 return (1); 745 return (0); 746} 747 748char * 749topdomain(h) 750 char *h; 751{ 752 register char *p; 753 char *maybe = NULL; 754 int dots = 0; 755 756 for (p = h + strlen(h); p >= h; p--) { 757 if (*p == '.') { 758 if (++dots == 2) 759 return (p); 760 maybe = p; 761 } 762 } 763 return (maybe); 764} 765