deraadt@cpsc.ucalgary.ca (Theo de Raadt) (05/24/91)
This archive contains the permissions library I wrote to control who could login to which machines on our network. It uses a YP map which specifies the permissions. sources to BSD versions of login, in.ftpd, and in.rshd are supplied which allready use the permissions lib. Share and Enjoy. Please clear all changes you make through me, as I don't want 10 incompatible versions on the net. <tdr. #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: examples in.ftpd in.rshd login perms permtest Makefile # README examples/cpsc.ucalgary.ca in.ftpd/Makefile in.ftpd/ftpcmd.y # in.ftpd/ftpd.c in.ftpd/glob.c in.ftpd/logwtmp.c in.ftpd/popen.c # in.ftpd/vers.c in.rshd/Makefile in.rshd/in.rshd.c login/Makefile # login/login.c perms/Makefile perms/glob_match.c perms/perms.y # permtest/Makefile permtest/permtest.c # Wrapped by deraadt@cpsc.ucalgary.ca on Thu May 23 22:54:53 1991 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test ! -d 'examples' ; then echo shar: Creating directory \"'examples'\" mkdir 'examples' fi if test ! -d 'in.ftpd' ; then echo shar: Creating directory \"'in.ftpd'\" mkdir 'in.ftpd' fi if test ! -d 'in.rshd' ; then echo shar: Creating directory \"'in.rshd'\" mkdir 'in.rshd' fi if test ! -d 'login' ; then echo shar: Creating directory \"'login'\" mkdir 'login' fi if test ! -d 'perms' ; then echo shar: Creating directory \"'perms'\" mkdir 'perms' fi if test ! -d 'permtest' ; then echo shar: Creating directory \"'permtest'\" mkdir 'permtest' fi if test -f 'Makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Makefile'\" else echo shar: Extracting \"'Makefile'\" \(247 characters\) sed "s/^X//" >'Makefile' <<'END_OF_FILE' Xall: X cd perms; $(MAKE) X cd permtest; $(MAKE) X cd login; $(MAKE) X cd in.rshd; $(MAKE) X cd in.ftpd; $(MAKE) X Xclean: X cd perms; $(MAKE) clean X cd permtest; $(MAKE) clean X cd login; $(MAKE) clean X cd in.rshd; $(MAKE) clean X cd in.ftpd; $(MAKE) clean END_OF_FILE if test 247 -ne `wc -c <'Makefile'`; then echo shar: \"'Makefile'\" unpacked with wrong size! fi # end of 'Makefile' fi if test -f 'README' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'README'\" else echo shar: Extracting \"'README'\" \(2484 characters\) sed "s/^X//" >'README' <<'END_OF_FILE' XDESCRIPTION: XIn a basic BSD environemt only three utilities let people onto a machine: X login, rshd, and ftpd. XThese three programs are modified to check a YP map called 'permissions' Xwhich determines whether a person is allowed to login. XControl over login is given based on four parameters: hostname, ttyname, Xlogin, and groups. X XThe permissions library routines have been tested on suns, iris, and mips Xboxes. The problem is not so much that permissions might be nonportable, Xbut rather that source for login is unavailable on the other machines I Xhave access to. Writing a workalike login for a system V box is nontrivial. Xpermtest, rshd and ftpd have been tested to work though, with minor hacks. XOn a BSD-like box, permissions should be trivial to install. X XPerhaps someone who has written a free system V login could send it to Xme. I'd love to support more architectures/operating systems. X XThe permissions library can be used for other purposes too. We also use it Xfor printer access. Someone suggested doing device access like dialin/dailout Xand tape drives through it. X XINSTALLATION: X1. Building permissions: X # make X2. Build a permissions map for your network and install it into YP. X See your systems manuals for the correct way to install a YP map X in your system. Here's what we use in /var/yp/Makefile, X Xpermissions.time: $(DIR)/permissions X @(sed -e "/^#/d" -e s/#.*$$// $(DIR)/permissions $(CHKPIPE)) | \ X $(MAKEDBM) - $(YPDBDIR)/$(DOM)/permissions; X @touch permissions.time; X @echo "updated permissions"; X @if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOM) permissions; fi X @if [ ! $(NOPUSH) ]; then echo "pushed permissions"; fi X X To install the map, on sunos4.1, I would use the following: X # touch /etc/permissions X # ypmake NOPUSH=1 permissions X # foreach i ( `ypcat ypservers` ) X > rsh $i /usr/etc/yp/ypxfr -h `hostname` permissions X > end X # X X5. Test the permissions database with permtest. For example, X # permtest -v deraadt ttyh0 fsa X 8 groups: staff wheel daemon kmem bin oldstaff telnet cdrom X user deraadt permitted on fsa:ttyh0 X X4. Now install the three remaining parts. X login/login -> /bin/login X in.ftpd/in.ftpd -> /usr/etc/in.ftpd X in.rshd/in.rshd -> /usr/etc/in.rshd X Be sure to save copies of your old utilities. X Remember, on most systems, login is setuid root. X XOne request. Please clear all changes to this through me. I would be very Xunhappy to see five different incompatible versions of this in use. X XEnjoy. Xderaadt@cpsc.ucalgary.ca END_OF_FILE if test 2484 -ne `wc -c <'README'`; then echo shar: \"'README'\" unpacked with wrong size! fi # end of 'README' fi if test -f 'examples/cpsc.ucalgary.ca' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'examples/cpsc.ucalgary.ca'\" else echo shar: Extracting \"'examples/cpsc.ucalgary.ca'\" \(4493 characters\) sed "s/^X//" >'examples/cpsc.ucalgary.ca' <<'END_OF_FILE' X# ---------------------------------------------------------------------- X# NIS map = permissions X# groked by: login, in.rshd, permtest, in.ftpd X# rsh and ftp generate tty field values of 'rsh' and 'ftp' X# X# SYNTAX: X# entry : hostname '\t' permlist X# permlist : permission `|` permlist X# | permission X# | null X# permission : ttylist ':' authlist X# | '$' entry -> #include an entry X# ttylist : tty ',' ttylist X# | tty -> tty regexp X# | null X# authlist : auth ',' authlist X# | auth X# auth : + spec -> add X# : - spec -> delete X# | null X# spec : user -> username to change X# | '.' group -> group regexp to change X# X# NOTES: X# Watch how we deny anonomous ftp on every machine with the $admin X# macro, then allow it on fsa again. fsa is our admin only machine, and X# does not actually run the ftpd included, but rather a logging ftpd. X# X# Two example users will explain the groups X# aycock is in groups: c510/L01, c461/L01, and c401/L01. (His account is X# actually in /home/c510/L01/aycock) X# deraadt is in groups: staff wheel daemonkmem bin telnet cdrom X# X# The macros at the top are very important. They groups machines into sets X# making their management easier. X# X# In some places you will see references to tty's. These are our fast modem X# racks. We restrict certain groups to using them. Others can go through the X# slower campus terminal servers. X# ---------------------------------------------------------------------- X X# macros Xadmin *:+.utils,+.staff,+.wheel,+operator | ftp:-ftp Xgrad_ws $admin | *:+.grads,+.profs,+.research,+.summer,+.gl,+.vlsi,+.srdg,+.c502/L01,+.c599/L01,+.c651/L01 Xprof_ws $admin | *:+.profs,+.research,+.srdg,+.offstaff Xvlsi_ws $admin | *:+.vlsi,+graham,+olthof,+jevans,+milligan Xoff_ws $admin | *:+.offstaff,+.profs Xug_ws $admin | $grad_ws | *:+.c[456]* X X# admin machines Xfsa $admin | ttyb,ttyh?:-.*,+.staff,+.uucp | *:+frangos,+elsie | ftp:+ftp Xaa $admin Xrat $admin | *:+aycock Xsev $admin Xatlas $admin | *:+test,-jamesm Xdudes $admin Xglags $admin X X# profs machines Xfsc $admin | *:+.grads,+.profs,+.research,+.srdg,+.vlsi,+.offstaff,+.c491/L01,+.banff,+.visitors | ttyj[0-6]:-.*,+.staff,+.profs,+.offstaff,+gl Xinterval $prof_ws Xca $prof_ws Xcb $prof_ws Xcc $prof_ws | *:+.gl Xcd $prof_ws | *:+.grads,+.research,+.srdg,+.vlsi,+joan Xce $prof_ws Xcf $prof_ws Xcg $prof_ws Xch $prof_ws Xic $prof_ws Xgolf $prof_ws Xalbert $prof_ws X X# grads machines Xfsd $admin | *:+.grads,+.profs,+.research,+.summer,+.vlsi,+gl,+.srdg,+.c502/L01,+.c599/L01,+.banff,+.arc,+conway | ttyh[0-6]:-.*,+.staff,+.profs,+.grads,+.vlsi,+.offstaff,+.research Xab $grad_ws | *:+publisher Xda $grad_ws Xdb $grad_ws Xdc $grad_ws | *:+joan Xdd $grad_ws Xde $grad_ws Xdf $grad_ws Xdg $grad_ws Xdh $grad_ws Xdi $grad_ws Xdj $grad_ws Xdk $grad_ws Xij $grad_ws X X# vlsi machines Xfsg $vlsi_ws Xga $vlsi_ws Xgb $vlsi_ws Xgc $vlsi_ws Xgd $vlsi_ws Xge $vlsi_ws Xgf $vlsi_ws Xgg $vlsi_ws Xgh $vlsi_ws X X# office staff machines Xia $off_ws Xih $off_ws X X# undergraduate workstations Xea $ug_ws Xeb $ug_ws Xec $ug_ws Xed $ug_ws Xee $ug_ws Xef $ug_ws Xeg $ug_ws Xeh $ug_ws Xei $ug_ws Xej $ug_ws Xha $ug_ws Xhb $ug_ws Xhc $ug_ws Xhd $ug_ws Xhe $ug_ws Xhf $ug_ws Xhg $ug_ws Xhh $ug_ws Xhi $ug_ws Xib $ug_ws Xid $ug_ws Xie $ug_ws Xif $ug_ws X X# graphicsland fileserver Xgfx $admin | *:+.gl,+thorne X X# myths. these machines do not run the right login yet. Xbfly $grad_ws Xirisa $admin | *:+.gl,+.c55[13]* Xirisb $admin | *:+.gl,+.c55[13]* Xirisc $admin | *:+.gl Xirisd $admin | *:+.gl Xirise $admin | *:+.gl Xirisf $admin | *:+.gl,+.c55[13]* X X# remaining machines. Anyone may use an undergrad machine. X# be careful - the $admin is at the end to turn off anon ftp X* *:+.*,-.uucp | $admin X X# PRINTERS X# Our printer permissions are done through permissions as well. Sorry, X# this distribution of permissions does not include our lpr hacks. X# I left this in here simply as an example. X Xlp1 *:+.*,-.nlp Xlp2 *:+.*,-.nlp X Xcs1 $admin | *:+.grads,+.research,+.profs,+.offstaff,+.srdg,+.submit | *:+.cs1,-.ncs1 Xcs2 $admin | *:+.grads,+.research,+.profs,+.offstaff,+.srdg,+.vlsi | *:+.cs2,-.ncs2 X Xalw1 $admin | *:+.profs,+.offstaff,+.grads | *:+.alw1,-.nalw1 Xalw2 $admin | *:+.profs,+.offstaff,+.vlsi | *:+.alw2,-.nalw2 Xalw3 $admin | *:+.grads,+.research,+.profs,+.srdg,+.vlsi | *:+.alw3,-.nalw3 Xalw4 $admin | *:+.grads,+.research,+.profs,+.offstaff,+.srdg,+.vlsi | *:+.alw4,-.nalw4 X Xbp $admin | *:+.bp,-.nbp Xip $admin | *:+.grads,+.research,+.profs,+.srdg,+.c481* | *:+.ip,-.nip END_OF_FILE if test 4493 -ne `wc -c <'examples/cpsc.ucalgary.ca'`; then echo shar: \"'examples/cpsc.ucalgary.ca'\" unpacked with wrong size! fi # end of 'examples/cpsc.ucalgary.ca' fi if test -f 'in.ftpd/Makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'in.ftpd/Makefile'\" else echo shar: Extracting \"'in.ftpd/Makefile'\" \(203 characters\) sed "s/^X//" >'in.ftpd/Makefile' <<'END_OF_FILE' XOBJ = ftpd.o ftpcmd.o glob.o popen.o logwtmp.o vers.o\ X ../perms/perms.o ../perms/glob_match.o XCFLAGS = -g -DPERMS X Xin.ftpd: $(OBJ) X $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJ) X Xclean: X $(RM) *.o *~ in.ftpd END_OF_FILE if test 203 -ne `wc -c <'in.ftpd/Makefile'`; then echo shar: \"'in.ftpd/Makefile'\" unpacked with wrong size! fi # end of 'in.ftpd/Makefile' fi if test -f 'in.ftpd/ftpcmd.y' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'in.ftpd/ftpcmd.y'\" else echo shar: Extracting \"'in.ftpd/ftpcmd.y'\" \(16052 characters\) sed "s/^X//" >'in.ftpd/ftpcmd.y' <<'END_OF_FILE' X/* X * Copyright (c) 1985, 1988 Regents of the University of California. X * All rights reserved. X * X * Redistribution and use in source and binary forms are permitted X * provided that the above copyright notice and this paragraph are X * duplicated in all such forms and that any documentation, X * advertising materials, and other materials related to such X * distribution and use acknowledge that the software was developed X * by the University of California, Berkeley. The name of the X * University may not be used to endorse or promote products derived X * from this software without specific prior written permission. X */ X X/* X * Grammar for FTP commands. X * See RFC 765. X */ X X%{ X X#ifndef lint Xstatic char sccsid[] = "@(#)ftpcmd.y 1.1 90/03/23 SMI"; /* from UCB 5.16 12/8/88 */ X#endif X X#include <sys/types.h> X#include <sys/socket.h> X X#include <netinet/in.h> X X#include <arpa/ftp.h> X X#include <stdio.h> X#include <signal.h> X#include <ctype.h> X#include <pwd.h> X#include <setjmp.h> X#include <syslog.h> X Xextern struct sockaddr_in data_dest; Xextern int logged_in; Xextern struct passwd *pw; Xextern int guest; Xextern int logging; Xextern int type; Xextern int form; Xextern int debug; Xextern int timeout; Xextern int pdata; Xextern char hostname[]; Xextern char *globerr; Xextern int usedefault; Xextern int transflag; Xextern char tmpline[]; Xchar **glob(); X Xstatic int cmd_type; Xstatic int cmd_form; Xstatic int cmd_bytesz; Xchar cbuf[512]; Xchar *fromname; X Xchar *index(); X%} X X%token X A B C E F I X L N P R S T X X SP CRLF COMMA STRING NUMBER X X USER PASS ACCT REIN QUIT PORT X PASV TYPE STRU MODE RETR STOR X APPE MLFL MAIL MSND MSOM MSAM X MRSQ MRCP ALLO REST RNFR RNTO X ABOR DELE CWD LIST NLST SITE X STAT HELP NOOP XMKD XRMD XPWD X XCUP STOU X X LEXERR X X%start cmd_list X X%% X Xcmd_list: /* empty */ X | cmd_list cmd X = { X fromname = (char *) 0; X } X | cmd_list rcmd X ; X Xcmd: USER SP username CRLF X = { X user((char *) $3); X free((char *) $3); X } X | PASS SP password CRLF X = { X pass((char *) $3); X free((char *) $3); X } X | PORT SP host_port CRLF X = { X usedefault = 0; X if (pdata >= 0) { X (void) close(pdata); X pdata = -1; X } X reply(200, "PORT command successful."); X } X | PASV CRLF X = { X passive(); X } X | TYPE SP type_code CRLF X = { X switch (cmd_type) { X X case TYPE_A: X if (cmd_form == FORM_N) { X reply(200, "Type set to A."); X type = cmd_type; X form = cmd_form; X } else X reply(504, "Form must be N."); X break; X X case TYPE_E: X reply(504, "Type E not implemented."); X break; X X case TYPE_I: X reply(200, "Type set to I."); X type = cmd_type; X break; X X case TYPE_L: X if (cmd_bytesz == 8) { X reply(200, X "Type set to L (byte size 8)."); X type = cmd_type; X } else X reply(504, "Byte size must be 8."); X } X } X | STRU SP struct_code CRLF X = { X switch ($3) { X X case STRU_F: X reply(200, "STRU F ok."); X break; X X default: X reply(504, "Unimplemented STRU type."); X } X } X | MODE SP mode_code CRLF X = { X switch ($3) { X X case MODE_S: X reply(200, "MODE S ok."); X break; X X default: X reply(502, "Unimplemented MODE type."); X } X } X | ALLO SP NUMBER CRLF X = { X reply(202, "ALLO command ignored."); X } X | RETR check_login SP pathname CRLF X = { X if ($2 && $4 != NULL) X retrieve((char *) 0, (char *) $4); X if ($4 != NULL) X free((char *) $4); X } X | STOR check_login SP pathname CRLF X = { X if ($2 && $4 != NULL) X store((char *) $4, "w", 0); X if ($4 != NULL) X free((char *) $4); X } X | APPE check_login SP pathname CRLF X = { X if ($2 && $4 != NULL) X store((char *) $4, "a", 0); X if ($4 != NULL) X free((char *) $4); X } X | NLST check_login CRLF X = { X if ($2) X retrieve("/bin/ls", ""); X } X | NLST check_login SP pathname CRLF X = { X if ($2 && $4 != NULL) X retrieve("/bin/ls %s", (char *) $4); X if ($4 != NULL) X free((char *) $4); X } X | LIST check_login CRLF X = { X if ($2) X retrieve("/bin/ls -lg", ""); X } X | LIST check_login SP pathname CRLF X = { X if ($2 && $4 != NULL) X retrieve("/bin/ls -lg %s", (char *) $4); X if ($4 != NULL) X free((char *) $4); X } X | DELE check_login SP pathname CRLF X = { X if ($2 && $4 != NULL) X delete((char *) $4); X if ($4 != NULL) X free((char *) $4); X } X | RNTO SP pathname CRLF X = { X if (fromname) { X renamecmd(fromname, (char *) $3); X free(fromname); X fromname = (char *) 0; X } else { X reply(503, "Bad sequence of commands."); X } X free((char *) $3); X } X | ABOR CRLF X = { X reply(225, "ABOR command successful."); X } X | CWD check_login CRLF X = { X if ($2) X cwd(pw->pw_dir); X } X | CWD check_login SP pathname CRLF X = { X if ($2 && $4 != NULL) X cwd((char *) $4); X if ($4 != NULL) X free((char *) $4); X } X | HELP CRLF X = { X help((char *) 0); X } X | HELP SP STRING CRLF X = { X help((char *) $3); X } X | NOOP CRLF X = { X reply(200, "NOOP command successful."); X } X | XMKD check_login SP pathname CRLF X = { X if ($2 && $4 != NULL) X makedir((char *) $4); X if ($4 != NULL) X free((char *) $4); X } X | XRMD check_login SP pathname CRLF X = { X if ($2 && $4 != NULL) X removedir((char *) $4); X if ($4 != NULL) X free((char *) $4); X } X | XPWD check_login CRLF X = { X if ($2) X pwd(); X } X | XCUP check_login CRLF X = { X if ($2) X cwd(".."); X } X | STOU check_login SP pathname CRLF X = { X if ($2 && $4 != NULL) X store((char *) $4, "w", 1); X if ($4 != NULL) X free((char *) $4); X } X | QUIT CRLF X = { X reply(221, "Goodbye."); X dologout(0); X } X | error CRLF X = { X yyerrok; X } X ; X Xrcmd: RNFR check_login SP pathname CRLF X = { X char *renamefrom(); X X if ($2 && $4) { X fromname = renamefrom((char *) $4); X if (fromname == (char *) 0 && $4) { X free((char *) $4); X } X } X } X ; X Xusername: STRING X ; X Xpassword: /* empty */ X = { X $$ = (int) ""; X } X | STRING X ; X Xbyte_size: NUMBER X ; X Xhost_port: NUMBER COMMA NUMBER COMMA NUMBER COMMA NUMBER COMMA X NUMBER COMMA NUMBER X = { X register char *a, *p; X X a = (char *)&data_dest.sin_addr; X a[0] = $1; a[1] = $3; a[2] = $5; a[3] = $7; X p = (char *)&data_dest.sin_port; X p[0] = $9; p[1] = $11; X data_dest.sin_family = AF_INET; X } X ; X Xform_code: N X = { X $$ = FORM_N; X } X | T X = { X $$ = FORM_T; X } X | C X = { X $$ = FORM_C; X } X ; X Xtype_code: A X = { X cmd_type = TYPE_A; X cmd_form = FORM_N; X } X | A SP form_code X = { X cmd_type = TYPE_A; X cmd_form = $3; X } X | E X = { X cmd_type = TYPE_E; X cmd_form = FORM_N; X } X | E SP form_code X = { X cmd_type = TYPE_E; X cmd_form = $3; X } X | I X = { X cmd_type = TYPE_I; X } X | L X = { X cmd_type = TYPE_L; X cmd_bytesz = 8; X } X | L SP byte_size X = { X cmd_type = TYPE_L; X cmd_bytesz = $3; X } X /* this is for a bug in the BBN ftp */ X | L byte_size X = { X cmd_type = TYPE_L; X cmd_bytesz = $2; X } X ; X Xstruct_code: F X = { X $$ = STRU_F; X } X | R X = { X $$ = STRU_R; X } X | P X = { X $$ = STRU_P; X } X ; X Xmode_code: S X = { X $$ = MODE_S; X } X | B X = { X $$ = MODE_B; X } X | C X = { X $$ = MODE_C; X } X ; X Xpathname: pathstring X = { X /* X * Problem: this production is used for all pathname X * processing, but only gives a 550 error reply. X * This is a valid reply in some cases but not in others. X */ X if (logged_in && $1 && strncmp((char *) $1, "~", 1) == 0) { X $$ = (int)*glob((char *) $1); X if (globerr != NULL) { X reply(550, globerr); X $$ = NULL; X } X free((char *) $1); X } else X $$ = $1; X } X ; X Xpathstring: STRING X ; X Xcheck_login: /* empty */ X = { X if (logged_in) X $$ = 1; X else { X reply(530, "Please login with USER and PASS."); X $$ = 0; X } X } X ; X X%% X Xextern jmp_buf errcatch; X X#define CMD 0 /* beginning of command */ X#define ARGS 1 /* expect miscellaneous arguments */ X#define STR1 2 /* expect SP followed by STRING */ X#define STR2 3 /* expect STRING */ X#define OSTR 4 /* optional SP then STRING */ X#define ZSTR1 5 /* SP then optional STRING */ X#define ZSTR2 6 /* optional STRING after SP */ X Xstruct tab { X char *name; X short token; X short state; X short implemented; /* 1 if command is implemented */ X char *help; X}; X Xstruct tab cmdtab[] = { /* In order defined in RFC 765 */ X { "USER", USER, STR1, 1, "<sp> username" }, X { "PASS", PASS, ZSTR1, 1, "<sp> password" }, X { "ACCT", ACCT, STR1, 0, "(specify account)" }, X { "REIN", REIN, ARGS, 0, "(reinitialize server state)" }, X { "QUIT", QUIT, ARGS, 1, "(terminate service)", }, X { "PORT", PORT, ARGS, 1, "<sp> b0, b1, b2, b3, b4" }, X { "PASV", PASV, ARGS, 1, "(set server in passive mode)" }, X { "TYPE", TYPE, ARGS, 1, "<sp> [ A | E | I | L ]" }, X { "STRU", STRU, ARGS, 1, "(specify file structure)" }, X { "MODE", MODE, ARGS, 1, "(specify transfer mode)" }, X { "RETR", RETR, STR1, 1, "<sp> file-name" }, X { "STOR", STOR, STR1, 1, "<sp> file-name" }, X { "APPE", APPE, STR1, 1, "<sp> file-name" }, X { "MLFL", MLFL, OSTR, 0, "(mail file)" }, X { "MAIL", MAIL, OSTR, 0, "(mail to user)" }, X { "MSND", MSND, OSTR, 0, "(mail send to terminal)" }, X { "MSOM", MSOM, OSTR, 0, "(mail send to terminal or mailbox)" }, X { "MSAM", MSAM, OSTR, 0, "(mail send to terminal and mailbox)" }, X { "MRSQ", MRSQ, OSTR, 0, "(mail recipient scheme question)" }, X { "MRCP", MRCP, STR1, 0, "(mail recipient)" }, X { "ALLO", ALLO, ARGS, 1, "allocate storage (vacuously)" }, X { "REST", REST, STR1, 0, "(restart command)" }, X { "RNFR", RNFR, STR1, 1, "<sp> file-name" }, X { "RNTO", RNTO, STR1, 1, "<sp> file-name" }, X { "ABOR", ABOR, ARGS, 1, "(abort operation)" }, X { "DELE", DELE, STR1, 1, "<sp> file-name" }, X { "CWD", CWD, OSTR, 1, "[ <sp> directory-name ]" }, X { "XCWD", CWD, OSTR, 1, "[ <sp> directory-name ]" }, X { "LIST", LIST, OSTR, 1, "[ <sp> path-name ]" }, X { "NLST", NLST, OSTR, 1, "[ <sp> path-name ]" }, X { "SITE", SITE, STR1, 0, "(get site parameters)" }, X { "STAT", STAT, OSTR, 0, "(get server status)" }, X { "HELP", HELP, OSTR, 1, "[ <sp> <string> ]" }, X { "NOOP", NOOP, ARGS, 1, "" }, X { "MKD", XMKD, STR1, 1, "<sp> path-name" }, X { "XMKD", XMKD, STR1, 1, "<sp> path-name" }, X { "RMD", XRMD, STR1, 1, "<sp> path-name" }, X { "XRMD", XRMD, STR1, 1, "<sp> path-name" }, X { "PWD", XPWD, ARGS, 1, "(return current directory)" }, X { "XPWD", XPWD, ARGS, 1, "(return current directory)" }, X { "CDUP", XCUP, ARGS, 1, "(change to parent directory)" }, X { "XCUP", XCUP, ARGS, 1, "(change to parent directory)" }, X { "STOU", STOU, STR1, 1, "<sp> file-name" }, X { NULL, 0, 0, 0, 0 } X}; X Xstruct tab * Xlookup(cmd) X char *cmd; X{ X register struct tab *p; X X for (p = cmdtab; p->name != NULL; p++) X if (strcmp(cmd, p->name) == 0) X return (p); X return (0); X} X X#include <arpa/telnet.h> X X/* X * getline - a hacked up version of fgets to ignore TELNET escape codes. X */ Xchar * Xgetline(s, n, iop) X char *s; X register FILE *iop; X{ X register c; X register char *cs; X X cs = s; X/* tmpline may contain saved command from urgent mode interruption */ X for (c = 0; tmpline[c] != '\0' && --n > 0; ++c) { X *cs++ = tmpline[c]; X if (tmpline[c] == '\n') { X *cs++ = '\0'; X if (debug) X syslog(LOG_DEBUG, "command: %s", s); X tmpline[0] = '\0'; X return(s); X } X if (c == 0) X tmpline[0] = '\0'; X } X while ((c = getc(iop)) != EOF) { X c &= 0377; X if (c == IAC) { X if ((c = getc(iop)) != EOF) { X c &= 0377; X switch (c) { X case WILL: X case WONT: X c = getc(iop); X printf("%c%c%c", IAC, DONT, 0377&c); X (void) fflush(stdout); X continue; X case DO: X case DONT: X c = getc(iop); X printf("%c%c%c", IAC, WONT, 0377&c); X (void) fflush(stdout); X continue; X case IAC: X break; X default: X continue; /* ignore command */ X } X } X } X *cs++ = c; X if (--n <= 0 || c == '\n') X break; X } X if (c == EOF && cs == s) X return (NULL); X *cs++ = '\0'; X if (debug) X syslog(LOG_DEBUG, "command: %s", s); X return (s); X} X Xstatic int Xtoolong() X{ X time_t now; X extern char *ctime(); X extern time_t time(); X X reply(421, X "Timeout (%d seconds): closing control connection.", timeout); X (void) time(&now); X if (logging) { X syslog(LOG_INFO, X "User %s timed out after %d seconds at %s", X (pw ? pw -> pw_name : "unknown"), timeout, ctime(&now)); X } X dologout(1); X} X Xyylex() X{ X static int cpos, state; X register char *cp; X register struct tab *p; X int n; X char c, *strpbrk(); X X for (;;) { X switch (state) { X X case CMD: X (void) signal(SIGALRM, toolong); X (void) alarm((unsigned) timeout); X if (getline(cbuf, sizeof(cbuf)-1, stdin) == NULL) { X reply(221, "You could at least say goodbye."); X dologout(0); X } X (void) alarm(0); X if ((cp = index(cbuf, '\r'))) { X *cp++ = '\n'; X *cp = '\0'; X } X if ((cp = strpbrk(cbuf, " \n"))) X cpos = cp - cbuf; X if (cpos == 0) X cpos = 4; X c = cbuf[cpos]; X cbuf[cpos] = '\0'; X upper(cbuf); X p = lookup(cbuf); X cbuf[cpos] = c; X if (p != 0) { X if (p->implemented == 0) { X nack(p->name); X longjmp(errcatch,0); X /* NOTREACHED */ X } X state = p->state; X yylval = (int) p->name; X return (p->token); X } X break; X X case OSTR: X if (cbuf[cpos] == '\n') { X state = CMD; X return (CRLF); X } X /* FALLTHROUGH */ X X case STR1: X case ZSTR1: X if (cbuf[cpos] == ' ') { X cpos++; X state = state == OSTR ? STR2 : ++state; X return (SP); X } X break; X X case ZSTR2: X if (cbuf[cpos] == '\n') { X state = CMD; X return (CRLF); X } X /* FALL THRU */ X X case STR2: X cp = &cbuf[cpos]; X n = strlen(cp); X cpos += n - 1; X /* X * Make sure the string is nonempty and \n terminated. X */ X if (n > 1 && cbuf[cpos] == '\n') { X cbuf[cpos] = '\0'; X yylval = copy(cp); X cbuf[cpos] = '\n'; X state = ARGS; X return (STRING); X } X break; X X case ARGS: X if (isdigit(cbuf[cpos])) { X cp = &cbuf[cpos]; X while (isdigit(cbuf[++cpos])) X ; X c = cbuf[cpos]; X cbuf[cpos] = '\0'; X yylval = atoi(cp); X cbuf[cpos] = c; X return (NUMBER); X } X switch (cbuf[cpos++]) { X X case '\n': X state = CMD; X return (CRLF); X X case ' ': X return (SP); X X case ',': X return (COMMA); X X case 'A': X case 'a': X return (A); X X case 'B': X case 'b': X return (B); X X case 'C': X case 'c': X return (C); X X case 'E': X case 'e': X return (E); X X case 'F': X case 'f': X return (F); X X case 'I': X case 'i': X return (I); X X case 'L': X case 'l': X return (L); X X case 'N': X case 'n': X return (N); X X case 'P': X case 'p': X return (P); X X case 'R': X case 'r': X return (R); X X case 'S': X case 's': X return (S); X X case 'T': X case 't': X return (T); X X } X break; X X default: X fatal("Unknown state in scanner."); X } X yyerror((char *) 0); X state = CMD; X longjmp(errcatch,0); X } X} X Xupper(s) X register char *s; X{ X while (*s != '\0') { X if (islower(*s)) X *s = toupper(*s); X s++; X } X} X Xcopy(s) X char *s; X{ X char *p; X extern char *malloc(), *strcpy(); X X p = malloc((unsigned) strlen(s) + 1); X if (p == NULL) X fatal("Ran out of memory."); X (void) strcpy(p, s); X return ((int)p); X} X Xhelp(s) X char *s; X{ X register struct tab *c; X register int width, NCMDS; X X width = 0, NCMDS = 0; X for (c = cmdtab; c->name != NULL; c++) { X int len = strlen(c->name) + 1; X X if (len > width) X width = len; X NCMDS++; X } X width = (width + 8) &~ 7; X if (s == 0) { X register int i, j, w; X int columns, lines; X X lreply(214, X "The following commands are recognized (* =>'s unimplemented)."); X columns = 76 / width; X if (columns == 0) X columns = 1; X lines = (NCMDS + columns - 1) / columns; X for (i = 0; i < lines; i++) { X printf(" "); X for (j = 0; j < columns; j++) { X c = cmdtab + j * lines + i; X printf("%s%c", c->name, X c->implemented ? ' ' : '*'); X if (c + lines >= &cmdtab[NCMDS]) X break; X w = strlen(c->name) + 1; X while (w < width) { X putchar(' '); X w++; X } X } X printf("\r\n"); X } X (void) fflush(stdout); X reply(214, "Direct comments to bugs@Sun.COM."); X return; X } X upper(s); X c = lookup(s); X if (c == (struct tab *)0) { X reply(502, "Unknown command %s.", s); X return; X } X if (c->implemented) X reply(214, "Syntax: %s %s", c->name, c->help); X else X reply(214, "%-*s\t%s; unimplemented.", width, c->name, c->help); X} END_OF_FILE if test 16052 -ne `wc -c <'in.ftpd/ftpcmd.y'`; then echo shar: \"'in.ftpd/ftpcmd.y'\" unpacked with wrong size! fi # end of 'in.ftpd/ftpcmd.y' fi if test -f 'in.ftpd/ftpd.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'in.ftpd/ftpd.c'\" else echo shar: Extracting \"'in.ftpd/ftpd.c'\" \(24225 characters\) sed "s/^X//" >'in.ftpd/ftpd.c' <<'END_OF_FILE' X/* X * Copyright (c) 1985, 1988 Regents of the University of California. X * All rights reserved. X * X * Redistribution and use in source and binary forms are permitted X * provided that the above copyright notice and this paragraph are X * duplicated in all such forms and that any documentation, X * advertising materials, and other materials related to such X * distribution and use acknowledge that the software was developed X * by the University of California, Berkeley. The name of the X * University may not be used to endorse or promote products derived X * from this software without specific prior written permission. X */ X X#ifndef lint Xchar copyright[] = X"@(#) Copyright (c) 1985, 1988 Regents of the University of California.\n\ X All rights reserved.\n"; X#endif not lint X X#ifndef lint Xstatic char sccsid[] = "@(#)ftpd.c 5.2 (Berkeley) 12/7/88"; X#endif not lint X X/* X * FTP server. X */ X#include <sys/param.h> X#include <sys/stat.h> X#include <sys/ioctl.h> X#include <sys/socket.h> X#include <sys/file.h> X#include <sys/wait.h> X X#include <netinet/in.h> X X#include <arpa/ftp.h> X#include <arpa/inet.h> X#include <arpa/telnet.h> X X#include <stdio.h> X#include <signal.h> X#include <pwd.h> X#ifdef PERMS X#include <string.h> X#include <grp.h> X#endif X#include <setjmp.h> X#include <netdb.h> X#include <errno.h> X#include <strings.h> X#include <syslog.h> X#include <varargs.h> X X/* X * File containing login names X * NOT to be used on this machine. X * Commonly used to disallow uucp. X */ X#define FTPUSERS "/etc/ftpusers" X Xextern int errno; Xextern char *sys_errlist[]; Xextern int sys_nerr; Xextern char *crypt(); Xextern char version[]; Xextern char *home; /* pointer to home directory for glob */ Xextern FILE *ftpd_popen(), *fopen(), *freopen(); Xextern int ftpd_pclose(), fclose(); Xextern char *getline(); Xextern char cbuf[]; X Xstruct sockaddr_in ctrl_addr; Xstruct sockaddr_in data_source; Xstruct sockaddr_in data_dest; Xstruct sockaddr_in his_addr; X Xint data; Xjmp_buf errcatch, urgcatch; Xint logged_in; Xstruct passwd *pw; Xint debug; Xint timeout = 900; /* timeout after 15 minutes of inactivity */ Xint logging; Xint guest; Xint type; Xint form; Xint stru; /* avoid C keyword */ Xint mode; Xint usedefault = 1; /* for data transfers */ Xint pdata = -1; /* for passive mode */ Xint transflag; Xint socksize = 24 * 1024; /* larger socket window size for data */ Xchar tmpline[7]; Xchar hostname[MAXHOSTNAMELEN]; Xchar remotehost[MAXHOSTNAMELEN]; Xchar buf[BUFSIZ*8]; /* larger buffer to speed up binary xfers */ X X/* X * Timeout intervals for retrying connections X * to hosts that don't accept PORT cmds. This X * is a kludge, but given the problems with TCP... X */ X#define SWAITMAX 90 /* wait at most 90 seconds */ X#define SWAITINT 5 /* interval between retries */ X Xint swaitmax = SWAITMAX; Xint swaitint = SWAITINT; X Xint lostconn(); Xint myoob(); XFILE *getdatasock(), *dataconn(); X Xmain(argc, argv) X int argc; X char *argv[]; X{ X int addrlen, on = 1; X char *cp; X#ifdef PERMS X char domainname[MAXHOSTNAMELEN]; X#endif X openlog("ftpd", LOG_PID, LOG_DAEMON); X addrlen = sizeof (his_addr); X if (getpeername(0, (struct sockaddr *)&his_addr, &addrlen) < 0) { X syslog(LOG_ERR, "getpeername (%s): %m",argv[0]); X exit(1); X } X addrlen = sizeof (ctrl_addr); X if (getsockname(0, (struct sockaddr *)&ctrl_addr, &addrlen) < 0) { X syslog(LOG_ERR, "getsockname (%s): %m",argv[0]); X exit(1); X } X data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1); X debug = 0; X argc--, argv++; X while (argc > 0 && *argv[0] == '-') { X for (cp = &argv[0][1]; *cp; cp++) switch (*cp) { X X case 'v': X debug = 1; X break; X X case 'd': X debug = 1; X break; X X case 'l': X logging = 1; X break; X X case 't': X timeout = atoi(++cp); X goto nextopt; X break; X X default: X fprintf(stderr, "ftpd: Unknown flag -%c ignored.\n", X *cp); X break; X } Xnextopt: X argc--, argv++; X } X (void) freopen("/dev/null", "w", stderr); X (void) signal(SIGPIPE, lostconn); X (void) signal(SIGCHLD, SIG_IGN); X if (signal(SIGURG, myoob) == BADSIG) X syslog(LOG_ERR, "signal: %m"); X /* handle urgent data inline */ X#ifdef SO_OOBINLINE X if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(on)) < 0) X syslog(LOG_ERR, "setsockopt: %m"); X#endif X if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1) X syslog(LOG_ERR, "fcntl F_SETOWN: %m"); X dolog(&his_addr); X /* do telnet option negotiation here */ X /* X * Set up default state X */ X data = -1; X type = TYPE_A; X form = FORM_N; X stru = STRU_F; X mode = MODE_S; X tmpline[0] = '\0'; X (void) gethostname(hostname, sizeof (hostname)); X#ifdef PERMS X if( Getdomainname(domainname, sizeof(domainname)) ) { X reply(220, "%s.%s FTP server (%s) ready.", X hostname, domainname, version); X } else { X reply(220, "%s FTP server (%s) ready.", X hostname, version); X } X#else X reply(220, "%s FTP server (%s) ready.", hostname, version); X#endif X (void) setjmp(errcatch); X for (;;) X (void) yyparse(); X} X Xlostconn() X{ X X if (debug) X syslog(LOG_DEBUG, "lost connection"); X dologout(-1); X} X Xstatic char ttyline[20]; X X/* X * Helper function for sgetpwnam(). X */ Xchar * Xsgetsave(s) X char *s; X{ X char *malloc(); X char *new = malloc((unsigned) strlen(s) + 1); X X if (new == NULL) { X reply(553, "Local resource failure: malloc"); X dologout(1); X } X (void) strcpy(new, s); X return (new); X} X X/* X * Save the result of a getpwnam. Used for USER command, since X * the data returned must not be clobbered by any other command X * (e.g., globbing). X */ Xstruct passwd * Xsgetpwnam(name) X char *name; X{ X static struct passwd save; X register struct passwd *p; X char *sgetsave(); X X if ((p = getpwnam(name)) == NULL) X return (p); X if (save.pw_name) { X free(save.pw_name); X free(save.pw_passwd); X free(save.pw_comment); X free(save.pw_gecos); X free(save.pw_dir); X free(save.pw_shell); X } X save = *p; X save.pw_name = sgetsave(p->pw_name); X save.pw_passwd = sgetsave(p->pw_passwd); X save.pw_comment = sgetsave(p->pw_comment); X save.pw_gecos = sgetsave(p->pw_gecos); X save.pw_dir = sgetsave(p->pw_dir); X save.pw_shell = sgetsave(p->pw_shell); X return (&save); X} X Xint login_attempts; /* number of failed login attempts */ Xint askpasswd; /* had user command, ask for passwd */ X X/* X * USER command. X * Sets global passwd pointer pw if named account exists X * and is acceptable; sets askpasswd if a PASS command is X * expected. If logged in previously, need to reset state. X * If name is "ftp" or "anonymous" and ftp account exists, X * set guest and pw, then just return. X * If account doesn't exist, ask for passwd anyway. X * Otherwise, check user requesting login privileges. X * Disallow anyone who does not have a standard X * shell returned by getusershell() (/etc/shells). X * Disallow anyone mentioned in the file FTPUSERS X * to allow people such as root and uucp to be avoided. X */ Xuser(name) X char *name; X{ X register char *cp; X FILE *fd; X char *shell; X char line[BUFSIZ], *index(), *getusershell(); X X if (logged_in) { X if (guest) { X reply(530, "Can't change user from guest login."); X return; X } X end_login(); X } X X guest = 0; X if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) { X if ((pw = sgetpwnam("ftp")) != NULL) { X#ifdef PERMS X if( checkuser(pw) ) { X reply(530, "Anon FTP not permitted here."); X pw = (struct passwd *) NULL; X return; X } X#endif X guest = 1; X askpasswd = 1; X reply(331, "Guest login ok, send ident as password."); X } else X reply(530, "User %s unknown.", name); X return; X } X if (pw = sgetpwnam(name)) { X#ifdef PERMS X if( checkuser(pw)) { X reply(530, "User %s access denied.", name); X pw = (struct passwd *) NULL; X return; X } X#endif X if ((shell = pw->pw_shell) == NULL || *shell == 0) X shell = "/bin/sh"; X while ((cp = getusershell()) != NULL) X if (strcmp(cp, shell) == 0) X break; X endusershell(); X if (cp == NULL) { X reply(530, "User %s access denied.", name); X pw = (struct passwd *) NULL; X return; X } X if ((fd = fopen(FTPUSERS, "r")) != NULL) { X while (fgets(line, sizeof (line), fd) != NULL) { X if ((cp = index(line, '\n')) != NULL) X *cp = '\0'; X if (strcmp(line, name) == 0) { X reply(530, "User %s access denied.", name); X pw = (struct passwd *) NULL; X return; X } X } X } X (void) fclose(fd); X } X reply(331, "Password required for %s.", name); X askpasswd = 1; X /* X * Delay before reading passwd after first failed X * attempt to slow down passwd-guessing programs. X */ X if (login_attempts) X sleep((unsigned) login_attempts); X} X X/* X * Terminate login as previous user, if any, resetting state; X * used when USER command is given or login fails. X */ Xend_login() X{ X X (void) seteuid((uid_t)0); X if (logged_in) X logwtmp(ttyline, "", ""); X pw = NULL; X logged_in = 0; X guest = 0; X} X Xpass(passwd) X char *passwd; X{ X char *xpasswd, *salt; X X if (logged_in || askpasswd == 0) { X reply(503, "Login with USER first."); X return; X } X askpasswd = 0; X if (!guest) { /* "ftp" is only account allowed no password */ X if (pw == NULL) X salt = "xx"; X else X salt = pw->pw_passwd; X xpasswd = crypt(passwd, salt); X /* The strcmp does not catch null passwords! */ X if (pw == NULL || *pw->pw_passwd == '\0' || X strcmp(xpasswd, pw->pw_passwd)) { X reply(530, "Login incorrect."); X pw = NULL; X if (login_attempts++ >= 5) { X syslog(LOG_ERR, X "repeated login failures from %s", X remotehost); X exit(0); X } X return; X } X } X login_attempts = 0; /* this time successful */ X (void) setegid((gid_t)pw->pw_gid); X (void) initgroups(pw->pw_name, pw->pw_gid); X if (chdir(pw->pw_dir)) { X if (chdir("/")) { X reply(550, "User %s: can't change directory to %s.", X pw->pw_name, pw->pw_dir); X goto bad; X } X } X X /* open wtmp before chroot */ X (void)sprintf(ttyline, "ftp%d", getpid()); X logwtmp(ttyline, pw->pw_name, remotehost); X logged_in = 1; X X if (guest && chroot(pw->pw_dir) < 0) { X reply(550, "Can't set guest privileges."); X goto bad; X } X if (seteuid((uid_t)pw->pw_uid) < 0) { X reply(550, "Can't set uid."); X goto bad; X } X if (guest) X reply(230, "Guest login ok, access restrictions apply."); X else X reply(230, "User %s logged in.", pw->pw_name); X home = pw->pw_dir; /* home dir for globbing */ X return; Xbad: X /* Forget all about it... */ X end_login(); X} X X/* X * return a printable type string X */ Xchar *print_type(t) X{ X switch (t) X { X case TYPE_A: return("ASCII "); X case TYPE_L: X case TYPE_I: return("Binary "); X } X return(""); X} X Xretrieve(cmd, name) X char *cmd, *name; X{ X FILE *fin, *dout; X struct stat st; X int (*closefunc)(), tmp; X void (*oldpipe)(); /* Hold value of SIGPIPE during close */ X X if (cmd == 0) { X fin = fopen(name, "r"), closefunc = fclose; X } else { X char line[BUFSIZ]; X X (void) sprintf(line, cmd, name), name = line; X fin = ftpd_popen(line, "r"), closefunc = ftpd_pclose; X } X if (fin == NULL) { X if (errno != 0) X perror_reply(550, name); X return; X } X st.st_size = 0; X if (cmd == 0 && X (stat(name, &st) < 0 || (st.st_mode&S_IFMT) != S_IFREG)) { X reply(550, "%s: not a plain file.", name); X goto done; X } X dout = dataconn(name, st.st_size, "w"); X if (dout == NULL) X goto done; X if ((tmp = send_data(fin, dout)) > 0 || ferror(dout) > 0) { X perror_reply(550, name); X } X else if (tmp == 0) { X reply(226, "%sTransfer complete.", print_type(type)); X } X /* X * If the transfer failed because the data connection got aborted, X * then the fclose may cause a SIGPIPE trying to flush the buffers X * and abort the whole session. Ignore SIGPIPEs during the fclose. X */ X oldpipe = signal(SIGPIPE, SIG_IGN); X (void) fclose(dout); X data = -1; X pdata = -1; X signal(SIGPIPE, oldpipe); Xdone: X (*closefunc)(fin); X} X Xstore(name, mode, unique) X char *name, *mode; X int unique; X{ X FILE *fout, *din; X int (*closefunc)(), tmp; X char *gunique(); X X { X struct stat st; X X if (unique && stat(name, &st) == 0 && X (name = gunique(name)) == NULL) X return; X fout = fopen(name, mode), closefunc = fclose; X } X if (fout == NULL) { X perror_reply(553, name); X return; X } X din = dataconn(name, (off_t)-1, "r"); X if (din == NULL) X goto done; X if ((tmp = receive_data(din, fout)) > 0 || ferror(fout) > 0) X perror_reply(552, name); X else if (tmp == 0) { X if (ferror(fout) > 0) X perror_reply(552, name); X else if (unique) X reply(226, "Transfer complete (unique file name:%s).", X name); X else X reply(226, "%sTransfer complete.", print_type(type)); X } X (void) fclose(din); X data = -1; X pdata = -1; Xdone: X (*closefunc)(fout); X} X XFILE * Xgetdatasock(mode) X char *mode; X{ X int s, on = 1; X X if (data >= 0) X return (fdopen(data, mode)); X s = socket(AF_INET, SOCK_STREAM, 0); X if (s < 0) X return (NULL); X (void) seteuid((uid_t)0); X if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof (on)) < 0) X goto bad; X /* anchor socket to avoid multi-homing problems */ X data_source.sin_family = AF_INET; X data_source.sin_addr = ctrl_addr.sin_addr; X if (bind(s, (struct sockaddr *)&data_source, sizeof (data_source)) < 0) X goto bad; X (void) seteuid((uid_t)pw->pw_uid); X return (fdopen(s, mode)); Xbad: X (void) seteuid((uid_t)pw->pw_uid); X (void) close(s); X return (NULL); X} X XFILE * Xdataconn(name, size, mode) X char *name; X off_t size; X char *mode; X{ X char sizebuf[32]; X FILE *file; X int retry = 0; X X if (size != (off_t) -1) X (void) sprintf (sizebuf, " (%ld bytes)", size); X else X (void) strcpy(sizebuf, ""); X if (pdata >= 0) { X struct sockaddr_in from; X int s, fromlen = sizeof(from); X X s = accept(pdata, (struct sockaddr *)&from, &fromlen); X if (s < 0) { X reply(425, "Can't open data connection."); X (void) close(pdata); X pdata = -1; X return(NULL); X } X (void) close(pdata); X pdata = s; X reply(150, "%sdata connection for %s (%s,%d)%s.", X print_type(type), X name, inet_ntoa(from.sin_addr), X ntohs(from.sin_port), sizebuf); X return(fdopen(pdata, mode)); X } X if (data >= 0) { X reply(125, "Using existing %sdata connection for %s%s.", X print_type(type), X name, sizebuf); X usedefault = 1; X return (fdopen(data, mode)); X } X if (usedefault) X data_dest = his_addr; X usedefault = 1; X file = getdatasock(mode); X if (file == NULL) { X reply(425, "Can't create data socket (%s,%d): %s.", X inet_ntoa(data_source.sin_addr), X ntohs(data_source.sin_port), X errno < sys_nerr ? sys_errlist[errno] : "unknown error"); X return (NULL); X } X data = fileno(file); X (void) setsockopt(data, SOL_SOCKET, SO_SNDBUF, (char *)&socksize, X sizeof (socksize)); X (void) setsockopt(data, SOL_SOCKET, SO_RCVBUF, (char *)&socksize, X sizeof (socksize)); X while (connect(data, &data_dest, sizeof (data_dest)) < 0) { X if (errno == EADDRINUSE && retry < swaitmax) { X sleep((unsigned) swaitint); X retry += swaitint; X continue; X } X perror_reply(425, "Can't build data connection"); X (void) fclose(file); X data = -1; X return (NULL); X } X reply(150, "%sdata connection for %s (%s,%d)%s.", X print_type(type), X name, inet_ntoa(data_dest.sin_addr), X ntohs(data_dest.sin_port), sizebuf); X return (file); X} X X/* X * Envelope for 'send_data_body'. Allow data connections to fail without X * terminating the daemon, but SIGPIPE is set to be ignored so that if X * one occurs on the data channel we'll just catch the error return on X * the write rather than causing the whole session to abort. X */ X Xsend_data(instr, outstr) X FILE *instr; /* Data being sent */ X FILE *outstr; /* Connection being transmitted upon */ X{ X int value; /* Return value from send_data_body */ X void (*oldpipe)(); /* Old handler for SIGPIPE */ X X oldpipe = signal(SIGPIPE, SIG_IGN); X value = send_data_body(instr, outstr); X signal(SIGPIPE, oldpipe); X return (value); X} X X/* X * Tranfer the contents of "instr" to X * "outstr" peer using the appropriate X * encapulation of the date subject X * to Mode, Structure, and Type. X * X * NB: Form isn't handled. X */ Xsend_data_body(instr, outstr) X FILE *instr, *outstr; X{ X register int c; X int netfd, filefd, cnt; X X transflag++; X if (setjmp(urgcatch)) { X transflag = 0; X return(-1); X } X switch (type) { X X case TYPE_A: X while ((c = getc(instr)) != EOF) { X if (c == '\n') { X if (ferror (outstr)) { X transflag = 0; X return (1); X } X (void) putc('\r', outstr); X } X (void) putc(c, outstr); X } X transflag = 0; X if (ferror (instr) || ferror (outstr)) { X return (1); X } X return (0); X X case TYPE_I: X case TYPE_L: X netfd = fileno(outstr); X filefd = fileno(instr); X X while ((cnt = read(filefd, buf, sizeof (buf))) > 0) { X if (write(netfd, buf, cnt) < 0) { X transflag = 0; X return (1); X } X } X transflag = 0; X return (cnt < 0); X } X reply(550, "Unimplemented TYPE %d in send_data", type); X transflag = 0; X return (-1); X} X X/* X * Transfer data from peer to X * "outstr" using the appropriate X * encapulation of the data subject X * to Mode, Structure, and Type. X * X * N.B.: Form isn't handled. X */ Xreceive_data(instr, outstr) X FILE *instr, *outstr; X{ X register int c; X int cnt; X X X transflag++; X if (setjmp(urgcatch)) { X transflag = 0; X return(-1); X } X switch (type) { X X case TYPE_I: X case TYPE_L: X while ((cnt = read(fileno(instr), buf, sizeof buf)) > 0) { X if (write(fileno(outstr), buf, cnt) < 0) { X transflag = 0; X return (1); X } X } X transflag = 0; X return (cnt < 0); X X case TYPE_E: X reply(553, "TYPE E not implemented."); X transflag = 0; X return (-1); X X case TYPE_A: X while ((c = getc(instr)) != EOF) { X while (c == '\r') { X if (ferror (outstr)) { X transflag = 0; X return (1); X } X if ((c = getc(instr)) != '\n') X (void) putc ('\r', outstr); X } X (void) putc (c, outstr); X } X transflag = 0; X if (ferror (instr) || ferror (outstr)) X return (1); X return (0); X } X transflag = 0; X fatal("Unknown type in receive_data."); X /*NOTREACHED*/ X} X Xfatal(s) X char *s; X{ X reply(451, "Error in server: %s\n", s); X reply(221, "Closing connection due to server error."); X dologout(0); X} X X/*VARARGS2*/ Xreply(n, s, va_alist) X int n; X char *s; X va_dcl X{ X va_list ap; X X va_start(ap); X printf("%d ", n); X _doprnt(s, ap, stdout); X printf("\r\n"); X (void) fflush(stdout); X if (debug) { X syslog(LOG_DEBUG, "<--- %d ", n); X vsyslog(LOG_DEBUG, s, ap); X } X va_end(ap); X} X X/*VARARGS2*/ Xlreply(n, s, va_alist) X int n; X char *s; X va_dcl X{ X va_list ap; X X va_start(ap); X printf("%d-", n); X _doprnt(s, ap, stdout); X printf("\r\n"); X (void) fflush(stdout); X if (debug) { X syslog(LOG_DEBUG, "<--- %d- ", n); X vsyslog(LOG_DEBUG, s, ap); X } X va_end(ap); X} X Xack(s) X char *s; X{ X reply(250, "%s command successful.", s); X} X Xnack(s) X char *s; X{ X reply(502, "%s command not implemented.", s); X} X X/* ARGSUSED */ Xyyerror(s) X char *s; X{ X char *cp; X X cp = index(cbuf,'\n'); X *cp = '\0'; X reply(500, "'%s': command not understood.",cbuf); X} X Xdelete(name) X char *name; X{ X struct stat st; X X if (stat(name, &st) < 0) { X perror_reply(550, name); X return; X } X if ((st.st_mode&S_IFMT) == S_IFDIR) { X if (rmdir(name) < 0) { X perror_reply(550, name); X return; X } X goto done; X } X if (unlink(name) < 0) { X perror_reply(550, name); X return; X } Xdone: X ack("DELE"); X} X Xcwd(path) X char *path; X{ X X if (chdir(path) < 0) { X perror_reply(550, path); X return; X } X ack("CWD"); X} X Xmakedir(name) X char *name; X{ X if (mkdir(name, 0777) < 0) X perror_reply(550, name); X else X reply(257, "MKD command successful."); X} X Xremovedir(name) X char *name; X{ X X if (rmdir(name) < 0) { X perror_reply(550, name); X return; X } X ack("RMD"); X} X Xpwd() X{ X char path[MAXPATHLEN + 1]; X extern char *getwd(); X X if (getwd(path) == (char *)NULL) { X reply(550, "%s.", path); X return; X } X reply(257, "\"%s\" is current directory.", path); X} X Xchar * Xrenamefrom(name) X char *name; X{ X struct stat st; X X if (stat(name, &st) < 0) { X perror_reply(550, name); X return ((char *)0); X } X reply(350, "File exists, ready for destination name"); X return (name); X} X Xrenamecmd(from, to) X char *from, *to; X{ X X if (rename(from, to) < 0) { X perror_reply(550, "rename"); X return; X } X ack("RNTO"); X} X Xdolog(sin) X struct sockaddr_in *sin; X{ X struct hostent *hp = gethostbyaddr((char *)&sin->sin_addr, X sizeof (struct in_addr), AF_INET); X time_t t, time(); X extern char *ctime(); X X if (hp) X (void) strncpy(remotehost, hp->h_name, sizeof (remotehost)); X else X (void) strncpy(remotehost, inet_ntoa(sin->sin_addr), X sizeof (remotehost)); X if (!logging) X return; X t = time((time_t *) 0); X syslog(LOG_INFO, "connection from %s at %s", X remotehost, ctime(&t)); X} X X/* X * Record logout in wtmp file X * and exit with supplied status. X */ Xdologout(status) X int status; X{ X if (logged_in) { X (void) seteuid((uid_t)0); X logwtmp(ttyline, "", ""); X } X /* beware of flushing buffers after a SIGPIPE */ X _exit(status); X} X Xmyoob() X{ X char *cp; X X /* only process if transfer occurring */ X if (!transflag) X return; X cp = tmpline; X if (getline(cp, 7, stdin) == NULL) { X reply(221, "You could at least say goodbye."); X dologout(0); X } X upper(cp); X if (strcmp(cp, "ABOR\r\n")) X return; X tmpline[0] = '\0'; X reply(426,"Transfer aborted. Data connection closed."); X reply(226,"Abort successful"); X longjmp(urgcatch, 1); X} X X/* X * Note: The 530 reply codes could be 4xx codes, except nothing is X * given in the state tables except 421 which implies an exit. (RFC959) X */ Xpassive() X{ X int len; X struct sockaddr_in tmp; X register char *p, *a; X X pdata = socket(AF_INET, SOCK_STREAM, 0); X if (pdata < 0) { X reply(530, "Can't open passive connection"); X return; X } X tmp = ctrl_addr; X tmp.sin_port = 0; X (void) seteuid((uid_t)0); X if (bind(pdata, (struct sockaddr *) &tmp, sizeof(tmp)) < 0) { X (void) seteuid((uid_t)pw->pw_uid); X (void) close(pdata); X pdata = -1; X reply(530, "Can't open passive connection"); X return; X } X (void) seteuid((uid_t)pw->pw_uid); X len = sizeof(tmp); X if (getsockname(pdata, (struct sockaddr *) &tmp, &len) < 0) { X (void) close(pdata); X pdata = -1; X reply(530, "Can't open passive connection"); X return; X } X if (listen(pdata, 1) < 0) { X (void) close(pdata); X pdata = -1; X reply(530, "Can't open passive connection"); X return; X } X a = (char *) &tmp.sin_addr; X p = (char *) &tmp.sin_port; X X#define UC(b) (((int) b) & 0xff) X X reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]), X UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1])); X} X X/* X * Generate unique name for file with basename "local". X * The file named "local" is already known to exist. X * Generates failure reply on error. X */ Xchar * Xgunique(local) X char *local; X{ X static char new[MAXPATHLEN]; X struct stat st; X char *cp = rindex(local, '/'); X int d, count=0; X X if (cp) X *cp = '\0'; X d = stat(cp ? local : ".", &st); X if (cp) X *cp = '/'; X if (d < 0) { X perror_reply(553, local); X return((char *) 0); X } X (void) strcpy(new, local); X cp = new + strlen(new); X *cp++ = '.'; X for (count = 1; count < 100; count++) { X (void) sprintf(cp, "%d", count); X if (stat(new, &st) < 0) X return(new); X } X reply(452, "Unique file name cannot be created."); X return((char *) 0); X} X X/* X * Format and send reply containing system error number. X */ Xperror_reply(code, string) X int code; X char *string; X{ X X if (errno < sys_nerr) X reply(code, "%s: %s.", string, sys_errlist[errno]); X else X reply(code, "%s: unknown error %d.", string, errno); X} X X#ifdef PERMS Xint XGetdomainname(s, n) Xchar *s; X{ X FILE *f; X char buf[200], *p; X int i = 0; X X f = fopen("/etc/resolv.conf", "r"); X if(!f) X return 0; X while( fgets(buf, sizeof buf, f) ) { X p = buf; X while(*p==' ' || *p=='\t') X p++; X if( strncmp(p, "domain", 6)) X continue; X p+= 6; X while(*p==' ' || *p=='\t') X p++; X while(*p!=' ' && *p!='\t' && *p!='\n' && *p!='\0' ) { X s[i++] = *p++; X if(i==n) X return 0; X } X s[i] = '\0'; X return 1; X } X} X Xcheckuser(pwd) Xstruct passwd *pwd; X{ X char *grpnames[NGROUPS+1]; X int ngrps, lp; X struct group *grp; X extern int permcheck(); X X setgrent(); X ngrps = 0; X if(!(grp=getgrgid(pwd->pw_gid))) { X syslog(LOG_CRIT, X "cannot find group name for %d\n", pwd->pw_gid); X goto broken_groups; X } X grpnames[ngrps++] = strdup(grp->gr_name); X while( grp=getgrent() ) { X if(pwd->pw_gid == grp->gr_gid) X continue; X while(*grp->gr_mem) { X if( !strcmp(pwd->pw_name, *grp->gr_mem)) { X grpnames[ngrps++] = strdup(grp->gr_name); X } X grp->gr_mem++; X } X } X endgrent(); X grpnames[ngrps] = NULL; X if( !permcheck(pw->pw_name, "ftp", grpnames, NULL) ) { X syslog(LOG_CRIT, X "%s:%s not permitted", "ftp", pw->pw_name); X return 1; X } Xbroken_groups: X return 0; X} X#endif END_OF_FILE if test 24225 -ne `wc -c <'in.ftpd/ftpd.c'`; then echo shar: \"'in.ftpd/ftpd.c'\" unpacked with wrong size! fi # end of 'in.ftpd/ftpd.c' fi if test -f 'in.ftpd/glob.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'in.ftpd/glob.c'\" else echo shar: Extracting \"'in.ftpd/glob.c'\" \(9587 characters\) sed "s/^X//" >'in.ftpd/glob.c' <<'END_OF_FILE' X/* X * Copyright (c) 1980 Regents of the University of California. X * All rights reserved. The Berkeley software License Agreement X * specifies the terms and conditions for redistribution. X */ X X#ifndef lint Xstatic char sccsid[] = "@(#)glob.c 5.2 (Berkeley) 3/7/86"; X#endif not lint X X/* X * C-shell glob for random programs. X */ X X#include <sys/param.h> X#include <sys/stat.h> X#include <sys/dir.h> X X#include <stdio.h> X#include <errno.h> X#include <pwd.h> X X#define QUOTE 0200 X#define TRIM 0177 X#define eq(a,b) (strcmp(a, b)==0) X#define GAVSIZ (NCARGS/6) X#define isdir(d) ((d.st_mode & S_IFMT) == S_IFDIR) X Xstatic char **gargv; /* Pointer to the (stack) arglist */ Xstatic short gargc; /* Number args in gargv */ Xstatic short gnleft; Xstatic short gflag; Xstatic int tglob(); Xchar **glob(); Xchar *globerr; Xchar *home; Xstruct passwd *getpwnam(); Xextern int errno; Xstatic char *strspl(), *strend(); Xchar *malloc(), *strcpy(), *strcat(); Xchar **copyblk(); X Xstatic int globcnt; X Xchar *globchars = "`{[*?"; X Xstatic char *gpath, *gpathp, *lastgpathp; Xstatic int globbed; Xstatic char *entp; Xstatic char **sortbas; X Xchar ** Xglob(v) X register char *v; X{ X char agpath[BUFSIZ]; X char *agargv[GAVSIZ]; X char *vv[2]; X vv[0] = v; X vv[1] = 0; X gflag = 0; X rscan(vv, tglob); X if (gflag == 0) X return (copyblk(vv)); X X globerr = 0; X gpath = agpath; gpathp = gpath; *gpathp = 0; X lastgpathp = &gpath[sizeof agpath - 2]; X ginit(agargv); globcnt = 0; X collect(v); X if (globcnt == 0 && (gflag&1)) { X blkfree(gargv), gargv = 0; X return (0); X } else X return (gargv = copyblk(gargv)); X} X Xstatic Xginit(agargv) X char **agargv; X{ X X agargv[0] = 0; gargv = agargv; sortbas = agargv; gargc = 0; X gnleft = NCARGS - 4; X} X Xstatic Xcollect(as) X register char *as; X{ X if (eq(as, "{") || eq(as, "{}")) { X Gcat(as, ""); X sort(); X } else X acollect(as); X} X Xstatic Xacollect(as) X register char *as; X{ X register int ogargc = gargc; X X gpathp = gpath; *gpathp = 0; globbed = 0; X expand(as); X if (gargc != ogargc) X sort(); X} X Xstatic Xsort() X{ X register char **p1, **p2, *c; X char **Gvp = &gargv[gargc]; X X p1 = sortbas; X while (p1 < Gvp-1) { X p2 = p1; X while (++p2 < Gvp) X if (strcmp(*p1, *p2) > 0) X c = *p1, *p1 = *p2, *p2 = c; X p1++; X } X sortbas = Gvp; X} X Xstatic Xexpand(as) X char *as; X{ X register char *cs; X register char *sgpathp, *oldcs; X struct stat stb; X X sgpathp = gpathp; X cs = as; X if (*cs == '~' && gpathp == gpath) { X addpath('~'); X for (cs++; letter(*cs) || digit(*cs) || *cs == '-';) X addpath(*cs++); X if (!*cs || *cs == '/') { X if (gpathp != gpath + 1) { X *gpathp = 0; X if (gethdir(gpath + 1)) X globerr = "Unknown user name after ~"; X (void) strcpy(gpath, gpath + 1); X } else X (void) strcpy(gpath, home); X gpathp = strend(gpath); X } X } X while (!any(*cs, globchars)) { X if (*cs == 0) { X if (!globbed) X Gcat(gpath, ""); X else if (stat(gpath, &stb) >= 0) { X Gcat(gpath, ""); X globcnt++; X } X goto endit; X } X addpath(*cs++); X } X oldcs = cs; X while (cs > as && *cs != '/') X cs--, gpathp--; X if (*cs == '/') X cs++, gpathp++; X *gpathp = 0; X if (*oldcs == '{') { X (void) execbrc(cs, ((char *)0)); X return; X } X matchdir(cs); Xendit: X gpathp = sgpathp; X *gpathp = 0; X} X Xstatic Xmatchdir(pattern) X char *pattern; X{ X struct stat stb; X register struct direct *dp; X DIR *dirp; X X dirp = opendir(gpath); X if (dirp == NULL) { X if (globbed) X return; X goto patherr2; X } X if (fstat(dirp->dd_fd, &stb) < 0) X goto patherr1; X if (!isdir(stb)) { X errno = ENOTDIR; X goto patherr1; X } X while ((dp = readdir(dirp)) != NULL) { X if (dp->d_ino == 0) X continue; X if (match(dp->d_name, pattern)) { X Gcat(gpath, dp->d_name); X globcnt++; X } X } X closedir(dirp); X return; X Xpatherr1: X closedir(dirp); Xpatherr2: X globerr = "Bad directory components"; X} X Xstatic Xexecbrc(p, s) X char *p, *s; X{ X char restbuf[BUFSIZ + 2]; X register char *pe, *pm, *pl; X int brclev = 0; X char *lm, savec, *sgpathp; X X for (lm = restbuf; *p != '{'; *lm++ = *p++) X continue; X for (pe = ++p; *pe; pe++) X switch (*pe) { X X case '{': X brclev++; X continue; X X case '}': X if (brclev == 0) X goto pend; X brclev--; X continue; X X case '[': X for (pe++; *pe && *pe != ']'; pe++) X continue; X continue; X } Xpend: X brclev = 0; X for (pl = pm = p; pm <= pe; pm++) X switch (*pm & (QUOTE|TRIM)) { X X case '{': X brclev++; X continue; X X case '}': X if (brclev) { X brclev--; X continue; X } X goto doit; X X case ','|QUOTE: X case ',': X if (brclev) X continue; Xdoit: X savec = *pm; X *pm = 0; X (void) strcpy(lm, pl); X (void) strcat(restbuf, pe + 1); X *pm = savec; X if (s == 0) { X sgpathp = gpathp; X expand(restbuf); X gpathp = sgpathp; X *gpathp = 0; X } else if (amatch(s, restbuf)) X return (1); X sort(); X pl = pm + 1; X if (brclev) X return (0); X continue; X X case '[': X for (pm++; *pm && *pm != ']'; pm++) X continue; X if (!*pm) X pm--; X continue; X } X if (brclev) X goto doit; X return (0); X} X Xstatic Xmatch(s, p) X char *s, *p; X{ X register int c; X register char *sentp; X char sglobbed = globbed; X X if (*s == '.' && *p != '.') X return (0); X sentp = entp; X entp = s; X c = amatch(s, p); X entp = sentp; X globbed = sglobbed; X return (c); X} X Xstatic Xamatch(s, p) X register char *s, *p; X{ X register int scc; X int ok, lc; X char *sgpathp; X struct stat stb; X int c, cc; X X globbed = 1; X for (;;) { X scc = *s++ & TRIM; X switch (c = *p++) { X X case '{': X return (execbrc(p - 1, s - 1)); X X case '[': X ok = 0; X lc = 077777; X while (cc = *p++) { X if (cc == ']') { X if (ok) X break; X return (0); X } X if (cc == '-') { X if (lc <= scc && scc <= *p++) X ok++; X } else X if (scc == (lc = cc)) X ok++; X } X if (cc == 0) X if (ok) X p--; X else X return 0; X continue; X X case '*': X if (!*p) X return (1); X if (*p == '/') { X p++; X goto slash; X } X s--; X do { X if (amatch(s, p)) X return (1); X } while (*s++); X return (0); X X case 0: X return (scc == 0); X X default: X if (c != scc) X return (0); X continue; X X case '?': X if (scc == 0) X return (0); X continue; X X case '/': X if (scc) X return (0); Xslash: X s = entp; X sgpathp = gpathp; X while (*s) X addpath(*s++); X addpath('/'); X if (stat(gpath, &stb) == 0 && isdir(stb)) X if (*p == 0) { X Gcat(gpath, ""); X globcnt++; X } else X expand(p); X gpathp = sgpathp; X *gpathp = 0; X return (0); X } X } X} X Xstatic XGmatch(s, p) X register char *s, *p; X{ X register int scc; X int ok, lc; X int c, cc; X X for (;;) { X scc = *s++ & TRIM; X switch (c = *p++) { X X case '[': X ok = 0; X lc = 077777; X while (cc = *p++) { X if (cc == ']') { X if (ok) X break; X return (0); X } X if (cc == '-') { X if (lc <= scc && scc <= *p++) X ok++; X } else X if (scc == (lc = cc)) X ok++; X } X if (cc == 0) X if (ok) X p--; X else X return 0; X continue; X X case '*': X if (!*p) X return (1); X for (s--; *s; s++) X if (Gmatch(s, p)) X return (1); X return (0); X X case 0: X return (scc == 0); X X default: X if ((c & TRIM) != scc) X return (0); X continue; X X case '?': X if (scc == 0) X return (0); X continue; X X } X } X} X Xstatic XGcat(s1, s2) X register char *s1, *s2; X{ X register int len = strlen(s1) + strlen(s2) + 1; X X if (len >= gnleft || gargc >= GAVSIZ - 1) X globerr = "Arguments too long"; X else { X gargc++; X gnleft -= len; X gargv[gargc] = 0; X gargv[gargc - 1] = strspl(s1, s2); X } X} X Xstatic Xaddpath(c) X char c; X{ X X if (gpathp >= lastgpathp) X globerr = "Pathname too long"; X else { X *gpathp++ = c; X *gpathp = 0; X } X} X Xstatic Xrscan(t, f) X register char **t; X int (*f)(); X{ X register char *p, c; X X while (p = *t++) { X if (f == tglob) X if (*p == '~') X gflag |= 2; X else if (eq(p, "{") || eq(p, "{}")) X continue; X while (c = *p++) X (*f)(c); X } X} X/* Xstatic Xscan(t, f) X register char **t; X int (*f)(); X{ X register char *p, c; X X while (p = *t++) X while (c = *p) X *p++ = (*f)(c); X} */ X Xstatic Xtglob(c) X register char c; X{ X X if (any(c, globchars)) X gflag |= c == '{' ? 2 : 1; X return (c); X} X/* Xstatic Xtrim(c) X char c; X{ X X return (c & TRIM); X} */ X X Xletter(c) X register char c; X{ X X return (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '_'); X} X Xdigit(c) X register char c; X{ X X return (c >= '0' && c <= '9'); X} X Xany(c, s) X register int c; X register char *s; X{ X X while (*s) X if (*s++ == c) X return(1); X return(0); X} Xblklen(av) X register char **av; X{ X register int i = 0; X X while (*av++) X i++; X return (i); X} X Xchar ** Xblkcpy(oav, bv) X char **oav; X register char **bv; X{ X register char **av = oav; X X while (*av++ = *bv++) X continue; X return (oav); X} X Xblkfree(av0) X char **av0; X{ X register char **av = av0; X X while (*av) X free(*av++); X free((char *)av0); X} X Xstatic Xchar * Xstrspl(cp, dp) X register char *cp, *dp; X{ X register char *ep = malloc((unsigned)(strlen(cp) + strlen(dp) + 1)); X X if (ep == (char *)0) X fatal("Out of memory"); X (void) strcpy(ep, cp); X (void) strcat(ep, dp); X return (ep); X} X Xchar ** Xcopyblk(v) X register char **v; X{ X register char **nv = (char **)malloc((unsigned)((blklen(v) + 1) * X sizeof(char **))); X if (nv == (char **)0) X fatal("Out of memory"); X X return (blkcpy(nv, v)); X} X Xstatic Xchar * Xstrend(cp) X register char *cp; X{ X X while (*cp) X cp++; X return (cp); X} X/* X * Extract a home directory from the password file X * The argument points to a buffer where the name of the X * user whose home directory is sought is currently. X * We write the home directory of the user back there. X */ Xgethdir(home) X char *home; X{ X register struct passwd *pp = getpwnam(home); X X if (pp == 0) X return (1); X (void) strcpy(home, pp->pw_dir); X return (0); X} END_OF_FILE if test 9587 -ne `wc -c <'in.ftpd/glob.c'`; then echo shar: \"'in.ftpd/glob.c'\" unpacked with wrong size! fi # end of 'in.ftpd/glob.c' fi if test -f 'in.ftpd/logwtmp.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'in.ftpd/logwtmp.c'\" else echo shar: Extracting \"'in.ftpd/logwtmp.c'\" \(1604 characters\) sed "s/^X//" >'in.ftpd/logwtmp.c' <<'END_OF_FILE' X/* X * Copyright (c) 1988 The Regents of the University of California. X * All rights reserved. X * X * Redistribution and use in source and binary forms are permitted X * provided that the above copyright notice and this paragraph are X * duplicated in all such forms and that any documentation, X * advertising materials, and other materials related to such X * distribution and use acknowledge that the software was developed X * by the University of California, Berkeley. The name of the X * University may not be used to endorse or promote products derived X * from this software without specific prior written permission. X */ X X#ifndef lint Xstatic char sccsid[] = "@(#)logwtmp.c 1.1 90/03/23 SMI"; /* from UCB 5.3 12/7/88 */ X#endif /* not lint */ X X#include <sys/types.h> X#include <sys/file.h> X#include <sys/time.h> X#include <sys/stat.h> X#include <utmp.h> X X#define WTMPFILE "/var/adm/wtmp" X Xstatic int fd = -1; X X/* X * Modified version of logwtmp that holds wtmp file open X * after first call, for use with ftp (which may chroot X * after login, but before logout). X */ Xlogwtmp(line, name, host) X char *line, *name, *host; X{ X struct utmp ut; X struct stat buf; X time_t time(); X char *strncpy(); X X if (fd < 0 && (fd = open(WTMPFILE, O_WRONLY|O_APPEND, 0)) < 0) X return; X if (fstat(fd, &buf) == 0) { X (void)strncpy(ut.ut_line, line, sizeof(ut.ut_line)); X (void)strncpy(ut.ut_name, name, sizeof(ut.ut_name)); X (void)strncpy(ut.ut_host, host, sizeof(ut.ut_host)); X (void)time(&ut.ut_time); X if (write(fd, (char *)&ut, sizeof(struct utmp)) != X sizeof(struct utmp)) X (void)ftruncate(fd, buf.st_size); X } X} END_OF_FILE if test 1604 -ne `wc -c <'in.ftpd/logwtmp.c'`; then echo shar: \"'in.ftpd/logwtmp.c'\" unpacked with wrong size! fi # end of 'in.ftpd/logwtmp.c' fi if test -f 'in.ftpd/popen.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'in.ftpd/popen.c'\" else echo shar: Extracting \"'in.ftpd/popen.c'\" \(3504 characters\) sed "s/^X//" >'in.ftpd/popen.c' <<'END_OF_FILE' X/* X * Copyright (c) 1988 The Regents of the University of California. X * All rights reserved. X * X * This code is derived from software written by Ken Arnold and X * published in UNIX Review, Vol. 6, No. 8. X * X * Redistribution and use in source and binary forms are permitted X * provided that the above copyright notice and this paragraph are X * duplicated in all such forms and that any documentation, X * advertising materials, and other materials related to such X * distribution and use acknowledge that the software was developed X * by the University of California, Berkeley. The name of the X * University may not be used to endorse or promote products derived X * from this software without specific prior written permission. X */ X X#ifndef lint Xstatic char sccsid[] = "@(#)popen.c 1.1 90/03/23 SMI"; /* from UCB 5.4 12/7/88 */ X#endif /* not lint */ X X#include <sys/types.h> X#include <sys/signal.h> X#include <sys/wait.h> X#include <stdio.h> X X/* X * Special version of popen which avoids call to shell. This insures noone X * may create a pipe to a hidden program as a side effect of a list or dir X * command. X */ Xstatic int *pids; Xstatic int fds; X XFILE * Xftpd_popen(program, type) X char *program, *type; X{ X register char *cp; X FILE *iop; X int argc, gargc, pdes[2], pid; X char **pop, *argv[100], *gargv[1000], *vv[2]; X extern char **glob(), **copyblk(), *strtok(), *malloc(); X X if (*type != 'r' && *type != 'w' || type[1]) X return(NULL); X X if (!pids) { X if ((fds = getdtablesize()) <= 0) X return(NULL); X if ((pids = (int *)malloc((u_int)(fds * sizeof(int)))) == NULL) X return(NULL); X bzero((char *)pids, fds * sizeof(int)); X } X if (pipe(pdes) < 0) X return(NULL); X X /* break up string into pieces */ X for (argc = 0, cp = program;; cp = NULL) X if (!(argv[argc++] = strtok(cp, " \t\n"))) X break; X X /* glob each piece */ X gargv[0] = argv[0]; X for (gargc = argc = 1; argv[argc]; argc++) { X if (!(pop = glob(argv[argc]))) { /* globbing failed */ X vv[0] = argv[argc]; X vv[1] = NULL; X pop = copyblk(vv); X } X argv[argc] = (char *)pop; /* save to free later */ X while (*pop && gargc < 1000) X gargv[gargc++] = *pop++; X } X gargv[gargc] = NULL; X X iop = NULL; X switch(pid = vfork()) { X case -1: /* error */ X (void)close(pdes[0]); X (void)close(pdes[1]); X goto free; X /* NOTREACHED */ X case 0: /* child */ X if (*type == 'r') { X if (pdes[1] != 1) { X /* X * Need to grab stderr too for new ls X */ X dup2(pdes[1], 2); X dup2(pdes[1], 1); X (void)close(pdes[1]); X } X (void)close(pdes[0]); X } else { X if (pdes[0] != 0) { X dup2(pdes[0], 0); X (void)close(pdes[0]); X } X (void)close(pdes[1]); X } X execv(gargv[0], gargv); X _exit(1); X } X /* parent; assume fdopen can't fail... */ X if (*type == 'r') { X iop = fdopen(pdes[0], type); X (void)close(pdes[1]); X } else { X iop = fdopen(pdes[1], type); X (void)close(pdes[0]); X } X pids[fileno(iop)] = pid; X Xfree: for (argc = 1; argv[argc] != NULL; argc++) X blkfree((char **)argv[argc]); X return(iop); X} X Xftpd_pclose(iop) X FILE *iop; X{ X register int fdes; X int omask; X union wait stat_loc; X int pid; X X /* X * pclose returns -1 if stream is not associated with a X * `popened' command, or, if already `pclosed'. X */ X if (pids == 0 || pids[fdes = fileno(iop)] == 0) X return(-1); X (void)fclose(iop); X omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP)); X while ((pid = wait(&stat_loc)) != pids[fdes] && pid != -1); X (void)sigsetmask(omask); X pids[fdes] = 0; X return(pid == -1 ? -1 : stat_loc.w_status); X} END_OF_FILE if test 3504 -ne `wc -c <'in.ftpd/popen.c'`; then echo shar: \"'in.ftpd/popen.c'\" unpacked with wrong size! fi # end of 'in.ftpd/popen.c' fi if test -f 'in.ftpd/vers.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'in.ftpd/vers.c'\" else echo shar: Extracting \"'in.ftpd/vers.c'\" \(64 characters\) sed "s/^X//" >'in.ftpd/vers.c' <<'END_OF_FILE' X/* @(#)vers.c 1.1 90/03/23 SMI */ Xchar version[] = "SunOS 4.1"; END_OF_FILE if test 64 -ne `wc -c <'in.ftpd/vers.c'`; then echo shar: \"'in.ftpd/vers.c'\" unpacked with wrong size! fi # end of 'in.ftpd/vers.c' fi if test -f 'in.rshd/Makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'in.rshd/Makefile'\" else echo shar: Extracting \"'in.rshd/Makefile'\" \(160 characters\) sed "s/^X//" >'in.rshd/Makefile' <<'END_OF_FILE' XOBJ = in.rshd.o ../perms/perms.o ../perms/glob_match.o XCFLAGS = -g -DPERMS X Xin.rshd: $(OBJ) X $(CC) $(LDFLAGS) $(OBJ) -o in.rshd X Xclean: X $(RM) *~ *.o in.rshd END_OF_FILE if test 160 -ne `wc -c <'in.rshd/Makefile'`; then echo shar: \"'in.rshd/Makefile'\" unpacked with wrong size! fi # end of 'in.rshd/Makefile' fi if test -f 'in.rshd/in.rshd.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'in.rshd/in.rshd.c'\" else echo shar: Extracting \"'in.rshd/in.rshd.c'\" \(6522 characters\) sed "s/^X//" >'in.rshd/in.rshd.c' <<'END_OF_FILE' X/* X * Copyright (c) 1983 Regents of the University of California. X * All rights reserved. The Berkeley software License Agreement X * specifies the terms and conditions for redistribution. X */ X X#ifndef lint Xchar copyright[] = X"@(#) Copyright (c) 1983 Regents of the University of California.\n\ X All rights reserved.\n"; X#endif not lint X X#ifndef lint Xstatic char sccsid[] = "@(#)rshd.c 5.7 (Berkeley) 5/9/86"; X#endif not lint X X/* X * remote shell server: X * remuser\0 X * locuser\0 X * command\0 X * data X */ X#include <sys/ioctl.h> X#include <sys/param.h> X#include <sys/socket.h> X#include <sys/time.h> X X#include <netinet/in.h> X X#include <arpa/inet.h> X X#include <stdio.h> X#include <errno.h> X#include <pwd.h> X#include <signal.h> X#include <netdb.h> X#include <syslog.h> X X X#ifdef PERMS X#include <grp.h> Xchar *strdup(), *grpnames[NGROUPS+1]; Xint ngrps, lp; Xstruct group *grp; Xextern int permcheck(); X#endif X Xint errno; Xchar *index(), *rindex(), *strncat(); X/*VARARGS1*/ Xint error(); X X/*ARGSUSED*/ Xmain(argc, argv) X int argc; X char **argv; X{ X struct linger linger; X int on = 1, fromlen; X struct sockaddr_in from; X X openlog("rsh", LOG_PID | LOG_ODELAY, LOG_DAEMON); X fromlen = sizeof (from); X if (getpeername(0, &from, &fromlen) < 0) { X fprintf(stderr, "%s: ", argv[0]); X perror("getpeername"); X _exit(1); X } X if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, X sizeof (on)) < 0) X syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); X linger.l_onoff = 1; X linger.l_linger = 60; /* XXX */ X if (setsockopt(0, SOL_SOCKET, SO_LINGER, (char *)&linger, X sizeof (linger)) < 0) X syslog(LOG_WARNING, "setsockopt (SO_LINGER): %m"); X doit(dup(0), &from); X} X Xchar username[20] = "USER="; Xchar homedir[64] = "HOME="; Xchar shell[64] = "SHELL="; Xchar *envinit[] = X {homedir, shell, "PATH=:/usr/ucb:/bin:/usr/bin", username, 0}; Xchar **environ; X Xdoit(f, fromp) X int f; X struct sockaddr_in *fromp; X{ X char cmdbuf[NCARGS+1], *cp; X char locuser[16], remuser[16]; X struct passwd *pwd; X int s; X struct hostent *hp; X char *hostname; X short port; X int pv[2], pid, ready, readfrom, cc; X char buf[BUFSIZ], sig; X int one = 1; X X (void) signal(SIGINT, SIG_DFL); X (void) signal(SIGQUIT, SIG_DFL); X (void) signal(SIGTERM, SIG_DFL); X#ifdef DEBUG X { int t = open("/dev/tty", 2); X if (t >= 0) { X ioctl(t, TIOCNOTTY, (char *)0); X (void) close(t); X } X } X#endif X fromp->sin_port = ntohs((u_short)fromp->sin_port); X if (fromp->sin_family != AF_INET || X fromp->sin_port >= IPPORT_RESERVED) { X syslog(LOG_ERR, "malformed from address\n"); X exit(1); X } X (void) alarm(60); X port = 0; X for (;;) { X char c; X if (read(f, &c, 1) != 1) { X syslog(LOG_ERR, "read: %m"); X shutdown(f, 1+1); X exit(1); X } X if (c == 0) X break; X port = port * 10 + c - '0'; X } X (void) alarm(0); X if (port != 0) { X int lport = IPPORT_RESERVED - 1; X s = rresvport(&lport); X if (s < 0) { X syslog(LOG_ERR, "can't get stderr port: %m"); X exit(1); X } X if (port >= IPPORT_RESERVED) { X syslog(LOG_ERR, "2nd port not reserved\n"); X exit(1); X } X fromp->sin_port = htons((u_short)port); X if (connect(s, fromp, sizeof (*fromp)) < 0) { X syslog(LOG_INFO, "connect second port: %m"); X exit(1); X } X } X dup2(f, 0); X dup2(f, 1); X dup2(f, 2); X hp = gethostbyaddr((char *)&fromp->sin_addr, sizeof (struct in_addr), X fromp->sin_family); X if (hp) X hostname = hp->h_name; X else X hostname = inet_ntoa(fromp->sin_addr); X getstr(remuser, sizeof(remuser), "remuser"); X getstr(locuser, sizeof(locuser), "locuser"); X getstr(cmdbuf, sizeof(cmdbuf), "command"); X setpwent(); X pwd = getpwnam(locuser); X if (pwd == NULL) { X error("Login incorrect.\n"); X exit(1); X } X endpwent(); X if (chdir(pwd->pw_dir) < 0) { X (void) chdir("/"); X#ifdef notdef X error("No remote directory.\n"); X exit(1); X#endif X } X if (pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0' && X ruserok(hostname, pwd->pw_uid == 0, remuser, locuser) < 0) { X error("Permission denied.\n"); X exit(1); X } X X#ifdef PERMS X /* build groups so we can look them up in 'permissions' X * this check is not run for uid 0 X */ X if(pwd->pw_uid != 0) { X setgrent(); X ngrps = 0; X grp=getgrgid(pwd->pw_gid); X grpnames[ngrps++] = strdup(grp->gr_name); X while( grp=getgrent() ) { X if(pwd->pw_gid == grp->gr_gid) X continue; X while(*grp->gr_mem) { X if( !strcmp(locuser, *grp->gr_mem)) { X grpnames[ngrps++] = strdup(grp->gr_name); X } X grp->gr_mem++; X } X } X endgrent(); X grpnames[ngrps] = NULL; X X lp = permcheck(locuser, "rsh", grpnames, NULL); X if(!lp) { X syslog(LOG_CRIT, X "rsh:%s not permitted", locuser); X error("Permission denied.\n"); X exit(1); X } X } X#endif X X (void) write(2, "\0", 1); X if (port) { X if (pipe(pv) < 0) { X error("Can't make pipe.\n"); X exit(1); X } X pid = fork(); X if (pid == -1) { X error("Try again.\n"); X exit(1); X } X if (pid) { X (void) close(0); (void) close(1); (void) close(2); X (void) close(f); (void) close(pv[1]); X readfrom = (1<<s) | (1<<pv[0]); X ioctl(pv[0], FIONBIO, (char *)&one); X /* should set s nbio! */ X do { X ready = readfrom; X if (select(16, &ready, (fd_set *)0, X (fd_set *)0, (struct timeval *)0) < 0) X break; X if (ready & (1<<s)) { X if (read(s, &sig, 1) <= 0) X readfrom &= ~(1<<s); X else X killpg(pid, sig); X } X if (ready & (1<<pv[0])) { X errno = 0; X cc = read(pv[0], buf, sizeof (buf)); X if (cc <= 0) { X shutdown(s, 1+1); X readfrom &= ~(1<<pv[0]); X } else X (void) write(s, buf, cc); X } X } while (readfrom); X exit(0); X } X setpgrp(0, getpid()); X (void) close(s); (void) close(pv[0]); X dup2(pv[1], 2); X } X if (*pwd->pw_shell == '\0') X pwd->pw_shell = "/bin/sh"; X (void) close(f); X (void) setgid((gid_t)pwd->pw_gid); X initgroups(pwd->pw_name, pwd->pw_gid); X (void) setuid((uid_t)pwd->pw_uid); X environ = envinit; X strncat(homedir, pwd->pw_dir, sizeof(homedir)-6); X strncat(shell, pwd->pw_shell, sizeof(shell)-7); X strncat(username, pwd->pw_name, sizeof(username)-6); X cp = rindex(pwd->pw_shell, '/'); X if (cp) X cp++; X else X cp = pwd->pw_shell; X execl(pwd->pw_shell, cp, "-c", cmdbuf, 0); X perror(pwd->pw_shell); X exit(1); X} X X/*VARARGS1*/ Xerror(fmt, a1, a2, a3) X char *fmt; X int a1, a2, a3; X{ X char buf[BUFSIZ]; X X buf[0] = 1; X (void) sprintf(buf+1, fmt, a1, a2, a3); X (void) write(2, buf, strlen(buf)); X} X Xgetstr(buf, cnt, err) X char *buf; X int cnt; X char *err; X{ X char c; X X do { X if (read(0, &c, 1) != 1) X exit(1); X *buf++ = c; X if (--cnt == 0) { X error("%s too long\n", err); X exit(1); X } X } while (c != 0); X} END_OF_FILE if test 6522 -ne `wc -c <'in.rshd/in.rshd.c'`; then echo shar: \"'in.rshd/in.rshd.c'\" unpacked with wrong size! fi # end of 'in.rshd/in.rshd.c' fi if test -f 'login/Makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'login/Makefile'\" else echo shar: Extracting \"'login/Makefile'\" \(164 characters\) sed "s/^X//" >'login/Makefile' <<'END_OF_FILE' XOBJ = login.o ../perms/perms.o ../perms/glob_match.o XCFLAGS = -g -DPERMS -DMAILPING X Xlogin: $(OBJ) X $(CC) $(LDFLAGS) $(OBJ) -o login X Xclean: X $(RM) *~ *.o login END_OF_FILE if test 164 -ne `wc -c <'login/Makefile'`; then echo shar: \"'login/Makefile'\" unpacked with wrong size! fi # end of 'login/Makefile' fi if test -f 'login/login.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'login/login.c'\" else echo shar: Extracting \"'login/login.c'\" \(15072 characters\) sed "s/^X//" >'login/login.c' <<'END_OF_FILE' X/* X * Copyright (c) 1980 Regents of the University of California. X * All rights reserved. The Berkeley software License Agreement X * specifies the terms and conditions for redistribution. X */ X X#ifndef lint Xchar copyright[] = X"@(#) Copyright (c) 1980 Regents of the University of California.\n\ X All rights reserved.\n"; X#endif not lint X X#ifndef lint Xstatic char sccsid[] = "@(#)login.c 5.15 (Berkeley) 4/12/86"; X#endif not lint X X/* X * login [ name ] X * login -r hostname (for rlogind) X * login -h hostname (for telnetd, etc.) X */ X X#include <sys/param.h> X#include <sys/stat.h> X#include <sys/time.h> X#include <sys/resource.h> X#include <sys/file.h> X X#include <sgtty.h> X#include <utmp.h> X#include <signal.h> X#include <pwd.h> X#include <stdio.h> X#include <lastlog.h> X#include <errno.h> X#include <ttyent.h> X#include <syslog.h> X#include <grp.h> X X#ifdef MAILPING X#include <sys/socket.h> X#include <netinet/in.h> X#include <netdb.h> Xchar mailhost[] = "mailhost"; X#endif X X#ifdef PERMS Xchar *strdup(), *grpnames[NGROUPS+1]; Xint ngrps, lp; Xstruct group *grp; Xextern int permcheck(); X#endif X X#define TTYGRPNAME "tty" /* name of group to own ttys */ X#define TTYGID(gid) tty_gid(gid) /* gid that owns all ttys */ X X#define SCMPN(a, b) strncmp(a, b, sizeof(a)) X#define SCPYN(a, b) strncpy(a, b, sizeof(a)) X X#define NMAX sizeof(utmp.ut_name) X#define HMAX sizeof(utmp.ut_host) X X#define FALSE 0 X#define TRUE -1 X X#define QUOTAWARN "/usr/ucb/quota -q" /* warn user about quotas */ X Xchar nolog[] = "/etc/nologin"; Xchar qlog[] = ".hushlogin"; Xchar maildir[30] = "/usr/spool/mail/"; Xchar lastlog[] = "/usr/adm/lastlog"; Xstruct passwd nouser = {"", "nope", -1, -1, -1, "", "", "", "" }; Xstruct sgttyb ttyb; Xstruct utmp utmp; Xchar minusnam[16] = "-"; Xchar *envinit[] = { 0 }; /* now set by setenv calls */ X/* X * This bounds the time given to login. We initialize it here X * so it can be patched on machines where it's too small. X */ Xint timeout = 60; X Xchar term[64]; X Xstruct passwd *pwd; Xchar *strcat(), *rindex(), *index(), *malloc(), *realloc(); Xint timedout(); Xchar *ttyname(); Xchar *crypt(); Xchar *getpass(); Xchar *stypeof(); Xextern char **environ; Xextern int errno; X Xstruct tchars tc = { X CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK X}; Xstruct ltchars ltc = { X CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT X}; X Xstruct winsize win = { 0, 0, 0, 0 }; X Xint rflag; Xint usererr = -1; Xchar rusername[NMAX+1], lusername[NMAX+1]; Xchar rpassword[NMAX+1]; Xchar name[NMAX+1]; Xchar *rhost; X Xmain(argc, argv) X char *argv[]; X{ X register char *namep; X int pflag = 0, hflag = 0, t, f, c; X int invalid, quietlog; X FILE *nlfd; X char *ttyn, *tty; X int ldisc = 0, zero = 0, i; X char **envnew; X X signal(SIGALRM, timedout); X alarm(timeout); X signal(SIGQUIT, SIG_IGN); X signal(SIGINT, SIG_IGN); X setpriority(PRIO_PROCESS, 0, 0); X /* X * -p is used by getty to tell login not to destroy the environment X * -r is used by rlogind to cause the autologin protocol; X * -h is used by other servers to pass the name of the X * remote host to login so that it may be placed in utmp and wtmp X */ X while (argc > 1) { X if (strcmp(argv[1], "-r") == 0) { X if (rflag || hflag) { X printf("Only one of -r and -h allowed\n"); X exit(1); X } X rflag = 1; X usererr = doremotelogin(argv[2]); X SCPYN(utmp.ut_host, argv[2]); X argc -= 2; X argv += 2; X continue; X } X if (strcmp(argv[1], "-h") == 0 && getuid() == 0) { X if (rflag || hflag) { X printf("Only one of -r and -h allowed\n"); X exit(1); X } X hflag = 1; X SCPYN(utmp.ut_host, argv[2]); X argc -= 2; X argv += 2; X continue; X } X if (strcmp(argv[1], "-p") == 0) { X argc--; X argv++; X pflag = 1; X continue; X } X break; X } X ioctl(0, TIOCLSET, &zero); X ioctl(0, TIOCNXCL, 0); X ioctl(0, FIONBIO, &zero); X ioctl(0, FIOASYNC, &zero); X ioctl(0, TIOCGETP, &ttyb); X /* X * If talking to an rlogin process, X * propagate the terminal type and X * baud rate across the network. X */ X if (rflag) X doremoteterm(term, &ttyb); X ttyb.sg_erase = CERASE; X ttyb.sg_kill = CKILL; X ioctl(0, TIOCSLTC, <c); X ioctl(0, TIOCSETC, &tc); X ioctl(0, TIOCSETP, &ttyb); X for (t = getdtablesize(); t > 2; t--) X close(t); X ttyn = ttyname(0); X if (ttyn == (char *)0 || *ttyn == '\0') X ttyn = "/dev/tty??"; X tty = rindex(ttyn, '/'); X if (tty == NULL) X tty = ttyn; X else X tty++; X openlog("login", LOG_ODELAY, LOG_AUTH); X t = 0; X invalid = FALSE; X do { X ldisc = 0; X ioctl(0, TIOCSETD, &ldisc); X SCPYN(utmp.ut_name, ""); X /* X * Name specified, take it. X */ X if (argc > 1) { X SCPYN(utmp.ut_name, argv[1]); X argc = 0; X } X /* X * If remote login take given name, X * otherwise prompt user for something. X */ X if (rflag && !invalid) X SCPYN(utmp.ut_name, lusername); X else X getloginname(&utmp); X invalid = FALSE; X if (!strcmp(pwd->pw_shell, "/bin/csh")) { X ldisc = NTTYDISC; X ioctl(0, TIOCSETD, &ldisc); X } X /* X * If no remote login authentication and X * a password exists for this user, prompt X * for one and verify it. X */ X if (usererr == -1 && *pwd->pw_passwd != '\0') { X char *pp; X X setpriority(PRIO_PROCESS, 0, -4); X pp = getpass("Password:"); X namep = crypt(pp, pwd->pw_passwd); X setpriority(PRIO_PROCESS, 0, 0); X if (strcmp(namep, pwd->pw_passwd)) X invalid = TRUE; X } X /* X * If user not super-user, check for logins disabled. X */ X if (pwd->pw_uid != 0 && (nlfd = fopen(nolog, "r")) > 0) { X while ((c = getc(nlfd)) != EOF) X putchar(c); X fflush(stdout); X sleep(5); X exit(0); X } X /* X * If valid so far and root is logging in, X * see if root logins on this terminal are permitted. X */ X if (!invalid && pwd->pw_uid == 0 && !rootterm(tty)) { X if (utmp.ut_host[0]) X syslog(LOG_CRIT, X "ROOT LOGIN REFUSED ON %s FROM %.*s", X tty, HMAX, utmp.ut_host); X else X syslog(LOG_CRIT, X "ROOT LOGIN REFUSED ON %s", tty); X invalid = TRUE; X } X#ifdef PERMS X /* build groups so we can look them up in 'permissions' X * this check is not run for uid 0 X */ X if(!invalid && pwd->pw_uid != 0) { X setgrent(); X ngrps = 0; X if(!(grp=getgrgid(pwd->pw_gid))) { X syslog(LOG_CRIT, X "cannot find group name for %d\n", pwd->pw_gid); X goto broken_groups; X } X grpnames[ngrps++] = strdup(grp->gr_name); X while( grp=getgrent() ) { X if(pwd->pw_gid == grp->gr_gid) X continue; X while(*grp->gr_mem) { X if( !strcmp(lusername, *grp->gr_mem)) { X grpnames[ngrps++] = strdup(grp->gr_name); X } X grp->gr_mem++; X } X } X endgrent(); X grpnames[ngrps] = NULL; X lp = permcheck(lusername, tty, grpnames, NULL); X if(!lp) { X syslog(LOG_CRIT, X "%s:%s not permitted", tty, lusername); X printf("Permission denied.\n"); X exit(1); X } X } Xbroken_groups: X#endif X if (invalid) { X printf("Login incorrect\n"); X if (++t >= 5) { X if (utmp.ut_host[0]) X syslog(LOG_CRIT, X "REPEATED LOGIN FAILURES ON %s FROM %.*s, %.*s", X tty, HMAX, utmp.ut_host, X NMAX, utmp.ut_name); X else X syslog(LOG_CRIT, X "REPEATED LOGIN FAILURES ON %s, %.*s", X tty, NMAX, utmp.ut_name); X ioctl(0, TIOCHPCL, (struct sgttyb *) 0); X close(0), close(1), close(2); X sleep(10); X exit(1); X } X } X if (*pwd->pw_shell == '\0') X pwd->pw_shell = "/bin/sh"; X if (chdir(pwd->pw_dir) < 0 && !invalid ) { X if (chdir("/") < 0) { X printf("No directory!\n"); X invalid = TRUE; X } else { X printf("No directory! %s\n", X "Logging in with home=/"); X pwd->pw_dir = "/"; X } X } X /* X * Remote login invalid must have been because X * of a restriction of some sort, no extra chances. X */ X if (!usererr && invalid) X exit(1); X } while (invalid); X/* committed to login turn off timeout */ X alarm(0); X X time(&utmp.ut_time); X t = ttyslot(); X if (t > 0 && (f = open("/etc/utmp", O_WRONLY)) >= 0) { X lseek(f, (long)(t*sizeof(utmp)), 0); X SCPYN(utmp.ut_line, tty); X write(f, (char *)&utmp, sizeof(utmp)); X close(f); X } X if ((f = open("/usr/adm/wtmp", O_WRONLY|O_APPEND)) >= 0) { X write(f, (char *)&utmp, sizeof(utmp)); X close(f); X } X quietlog = access(qlog, F_OK) == 0; X if ((f = open(lastlog, O_RDWR)) >= 0) { X struct lastlog ll; X X lseek(f, (long)pwd->pw_uid * sizeof (struct lastlog), 0); X if (read(f, (char *) &ll, sizeof ll) == sizeof ll && X ll.ll_time != 0 && !quietlog) { X printf("Last login: %.*s ", X 24-5, (char *)ctime(&ll.ll_time)); X if (*ll.ll_host != '\0') X printf("from %.*s\n", X sizeof (ll.ll_host), ll.ll_host); X else X printf("on %.*s\n", X sizeof (ll.ll_line), ll.ll_line); X } X lseek(f, (long)pwd->pw_uid * sizeof (struct lastlog), 0); X time(&ll.ll_time); X SCPYN(ll.ll_line, tty); X SCPYN(ll.ll_host, utmp.ut_host); X write(f, (char *) &ll, sizeof ll); X close(f); X } X chown(ttyn, pwd->pw_uid, TTYGID(pwd->pw_gid)); X if (!hflag && !rflag) /* XXX */ X ioctl(0, TIOCSWINSZ, &win); X chmod(ttyn, 0620); X setgid(pwd->pw_gid); X strncpy(name, utmp.ut_name, NMAX); X name[NMAX] = '\0'; X initgroups(name, pwd->pw_gid); X setuid(pwd->pw_uid); X /* destroy environment unless user has asked to preserve it */ X if (!pflag) X environ = envinit; X X /* set up environment, this time without destruction */ X /* copy the environment before setenving */ X i = 0; X while (environ[i] != NULL) X i++; X envnew = (char **) malloc(sizeof (char *) * (i + 1)); X for (; i >= 0; i--) X envnew[i] = environ[i]; X environ = envnew; X X setenv("HOME=", pwd->pw_dir, 1); X setenv("SHELL=", pwd->pw_shell, 1); X if (term[0] == '\0') X strncpy(term, stypeof(tty), sizeof(term)); X setenv("TERM=", term, 0); X setenv("USER=", pwd->pw_name, 1); X setenv("PATH=", ":/usr/ucb:/bin:/usr/bin", 0); X X if ((namep = rindex(pwd->pw_shell, '/')) == NULL) X namep = pwd->pw_shell; X else X namep++; X strcat(minusnam, namep); X if (tty[sizeof("tty")-1] == 'd') X syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name); X if (pwd->pw_uid == 0) X if (utmp.ut_host[0]) X syslog(LOG_NOTICE, "ROOT LOGIN %s FROM %.*s", X tty, HMAX, utmp.ut_host); X else X syslog(LOG_NOTICE, "ROOT LOGIN %s", tty); X if (!quietlog) { X struct stat st; X X showmotd(); X strcat(maildir, pwd->pw_name); X#ifdef MAILPING X if(!serverup()) X printf("No idea if you have mail.\n"); X else X#endif X if (stat(maildir, &st) == 0 && st.st_size != 0) X printf("You have %smail.\n", X (st.st_mtime > st.st_atime) ? "new " : ""); X system(QUOTAWARN); X } X signal(SIGALRM, SIG_DFL); X signal(SIGQUIT, SIG_DFL); X signal(SIGINT, SIG_DFL); X signal(SIGTSTP, SIG_IGN); X execlp(pwd->pw_shell, minusnam, 0); X perror(pwd->pw_shell); X printf("No shell\n"); X exit(0); X} X Xgetloginname(up) X register struct utmp *up; X{ X register char *namep; X char c; X X while (up->ut_name[0] == '\0') { X namep = up->ut_name; X printf("login: "); X while ((c = getchar()) != '\n') { X if (c == ' ') X c = '_'; X if (c == EOF) X exit(0); X if (namep < up->ut_name+NMAX) X *namep++ = c; X } X } X strncpy(lusername, up->ut_name, NMAX); X lusername[NMAX] = 0; X if ((pwd = getpwnam(lusername)) == NULL) X pwd = &nouser; X} X Xtimedout() X{ X X printf("Login timed out after %d seconds\n", timeout); X exit(0); X} X Xint stopmotd; Xcatch() X{ X X signal(SIGINT, SIG_IGN); X stopmotd++; X} X Xrootterm(tty) X char *tty; X{ X register struct ttyent *t; X X if ((t = getttynam(tty)) != NULL) { X if (t->ty_status & TTY_SECURE) X return (1); X } X return (0); X} X Xshowmotd() X{ X FILE *mf; X register c; X X signal(SIGINT, catch); X if ((mf = fopen("/etc/motd", "r")) != NULL) { X while ((c = getc(mf)) != EOF && stopmotd == 0) X putchar(c); X fclose(mf); X } X signal(SIGINT, SIG_IGN); X} X X#undef UNKNOWN X#define UNKNOWN "su" X Xchar * Xstypeof(ttyid) X char *ttyid; X{ X register struct ttyent *t; X X if (ttyid == NULL || (t = getttynam(ttyid)) == NULL) X return (UNKNOWN); X return (t->ty_type); X} X Xdoremotelogin(host) X char *host; X{ X getstr(rusername, sizeof (rusername), "remuser"); X getstr(lusername, sizeof (lusername), "locuser"); X getstr(term, sizeof(term), "Terminal type"); X if (getuid()) { X pwd = &nouser; X return(-1); X } X pwd = getpwnam(lusername); X if (pwd == NULL) { X pwd = &nouser; X return(-1); X } X return(ruserok(host, (pwd->pw_uid == 0), rusername, lusername)); X} X Xgetstr(buf, cnt, err) X char *buf; X int cnt; X char *err; X{ X char c; X X do { X if (read(0, &c, 1) != 1) X exit(1); X if (--cnt < 0) { X printf("%s too long\r\n", err); X exit(1); X } X *buf++ = c; X } while (c != 0); X} X Xchar *speeds[] = X { "0", "50", "75", "110", "134", "150", "200", "300", X "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" }; X#define NSPEEDS (sizeof (speeds) / sizeof (speeds[0])) X Xdoremoteterm(term, tp) X char *term; X struct sgttyb *tp; X{ X register char *cp = index(term, '/'), **cpp; X char *speed; X X if (cp) { X *cp++ = '\0'; X speed = cp; X cp = index(speed, '/'); X if (cp) X *cp++ = '\0'; X for (cpp = speeds; cpp < &speeds[NSPEEDS]; cpp++) X if (strcmp(*cpp, speed) == 0) { X tp->sg_ispeed = tp->sg_ospeed = cpp-speeds; X break; X } X } X tp->sg_flags = ECHO|CRMOD|ANYP|XTABS; X} X X/* X * Set the value of var to be arg in the Unix 4.2 BSD environment env. X * Var should end with '='. X * (bindings are of the form "var=value") X * This procedure assumes the memory for the first level of environ X * was allocated using malloc. X */ Xsetenv(var, value, clobber) X char *var, *value; X{ X extern char **environ; X int index = 0; X int varlen = strlen(var); X int vallen = strlen(value); X X for (index = 0; environ[index] != NULL; index++) { X if (strncmp(environ[index], var, varlen) == 0) { X /* found it */ X if (!clobber) X return; X environ[index] = malloc(varlen + vallen + 1); X strcpy(environ[index], var); X strcat(environ[index], value); X return; X } X } X environ = (char **) realloc(environ, sizeof (char *) * (index + 2)); X if (environ == NULL) { X fprintf(stderr, "login: malloc out of memory\n"); X exit(1); X } X environ[index] = malloc(varlen + vallen + 1); X strcpy(environ[index], var); X strcat(environ[index], value); X environ[++index] = NULL; X} X Xtty_gid(default_gid) X int default_gid; X{ X struct group *getgrnam(), *gr; X int gid = default_gid; X X gr = getgrnam(TTYGRPNAME); X if (gr != (struct group *) 0) X gid = gr->gr_gid; X X endgrent(); X X return (gid); X} X X#ifdef MAILPING X/* ping mailhost, at port echo/udp X * determine if server is up=1 X * if unable, default to down=0 X */ Xserverup() X{ X struct sockaddr_in sin; X struct hostent *hent; X struct servent *sent; X struct timeval tv; X int s, count, tsize; X fd_set fdin; X X if( !(hent=gethostbyname(mailhost))) X return 0; X if( !(sent=getservbyname("echo", "udp"))) X return 0; X X bzero(&sin, sizeof sin); X sin.sin_family = hent->h_addrtype; X bcopy((char *)hent->h_addr, (char *)&sin.sin_addr, hent->h_length); X sin.sin_port = sent->s_port; X X if( (s=socket(AF_INET, SOCK_DGRAM, 0)) <0) X return 0; X X tsize = getdtablesize(); X tv.tv_sec = 1; X tv.tv_usec = 0; X for(count=0; count<10; count++) { X FD_ZERO(&fdin); X FD_SET(s, &fdin); X switch( select(tsize, &fdin, NULL, NULL, &tv) ) { X case -1: X perror("select"); X break; X case 0: X if( sendto(s, "UP?", 3, 0, &sin, sizeof sin) < 0) X perror("sendto"); X break; X case 1: X close(s); X return 1; X } X } X X close(s); X return 0; X} X#endif END_OF_FILE if test 15072 -ne `wc -c <'login/login.c'`; then echo shar: \"'login/login.c'\" unpacked with wrong size! fi # end of 'login/login.c' fi if test -f 'perms/Makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'perms/Makefile'\" else echo shar: Extracting \"'perms/Makefile'\" \(293 characters\) sed "s/^X//" >'perms/Makefile' <<'END_OF_FILE' XYACCFLAGS = -d XOBJ = perms.o glob_match.o XCFLAGS = -g -DPERMS X Xall: glob_match.o perms.o X Xperms.o: perms.y X yacc $(YACCFLAGS) perms.y X sed -e "s/yy/xx/g" -e "s/YY/XX/g" y.tab.c > x.tab.c X $(CC) $(CFLAGS) -c x.tab.c -o perms.o X $(RM) y.tab.c x.tab.c X Xclean: X $(RM) *~ *.o y.tab.h y.tab.c END_OF_FILE if test 293 -ne `wc -c <'perms/Makefile'`; then echo shar: \"'perms/Makefile'\" unpacked with wrong size! fi # end of 'perms/Makefile' fi if test -f 'perms/glob_match.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'perms/glob_match.c'\" else echo shar: Extracting \"'perms/glob_match.c'\" \(7660 characters\) sed "s/^X//" >'perms/glob_match.c' <<'END_OF_FILE' X/* File-name wildcard pattern matching for GNU. X Copyright (C) 1985, 1988 Free Software Foundation, Inc. X X NO WARRANTY X X BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY XNO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT XWHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC, XRICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS PROGRAM "AS IS" XWITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, XBUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND XFITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY XAND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE XDEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR XCORRECTION. X X IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M. XSTALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY XWHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE XLIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR XOTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE XUSE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR XDATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR XA FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS XPROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH XDAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY. X X GENERAL PUBLIC LICENSE TO COPY X X 1. You may copy and distribute verbatim copies of this source file Xas you receive it, in any medium, provided that you conspicuously and Xappropriately publish on each copy a valid copyright notice "Copyright X(C) 1988 Free Software Foundation, Inc."; and include following the Xcopyright notice a verbatim copy of the above disclaimer of warranty Xand of this License. X X 2. You may modify your copy or copies of this source file or Xany portion of it, and copy and distribute such modifications under Xthe terms of Paragraph 1 above, provided that you also do the following: X X a) cause the modified files to carry prominent notices stating X that you changed the files and the date of any change; and X X b) cause the whole of any work that you distribute or publish, X that in whole or in part contains or is a derivative of this X program or any part thereof, to be licensed at no charge to all X third parties on terms identical to those contained in this X License Agreement (except that you may choose to grant more extensive X warranty protection to some or all third parties, at your option). X X c) You may charge a distribution fee for the physical act of X transferring a copy, and you may at your option offer warranty X protection in exchange for a fee. X XMere aggregation of another unrelated program with this program (or its Xderivative) on a volume of a storage or distribution medium does not bring Xthe other program under the scope of these terms. X X 3. You may copy and distribute this program (or a portion or derivative Xof it, under Paragraph 2) in object code or executable form under the terms Xof Paragraphs 1 and 2 above provided that you also do one of the following: X X a) accompany it with the complete corresponding machine-readable X source code, which must be distributed under the terms of X Paragraphs 1 and 2 above; or, X X b) accompany it with a written offer, valid for at least three X years, to give any third party free (except for a nominal X shipping charge) a complete machine-readable copy of the X corresponding source code, to be distributed under the terms of X Paragraphs 1 and 2 above; or, X X c) accompany it with the information you received as to where the X corresponding source code may be obtained. (This alternative is X allowed only for noncommercial distribution and only if you X received the program in object code or executable form alone.) X XFor an executable file, complete source code means all the source code for Xall modules it contains; but, as a special exception, it need not include Xsource code for modules which are standard libraries that accompany the Xoperating system on which the executable file runs. X X 4. You may not copy, sublicense, distribute or transfer this program Xexcept as expressly provided under this License Agreement. Any attempt Xotherwise to copy, sublicense, distribute or transfer this program is void and Xyour rights to use the program under this License agreement shall be Xautomatically terminated. However, parties who have received computer Xsoftware programs from you with this License Agreement will not have Xtheir licenses terminated so long as such parties remain in full compliance. X X XIn other words, you are welcome to use, share and improve this program. XYou are forbidden to forbid anyone else to use, share and improve Xwhat you give them. Help stamp out software-hoarding! */ X X/* Match the pattern PATTERN against the string TEXT; X return 1 if it matches, 0 otherwise. X X A match means the entire string TEXT is used up in matching. X X In the pattern string, `*' matches any sequence of characters, X `?' matches any character, [SET] matches any character in the specified set, X [^SET] matches any character not in the specified set. X X A set is composed of characters or ranges; a range looks like X character hyphen character (as in 0-9 or A-Z). X [0-9a-zA-Z_] is the set of characters allowed in C identifiers. X Any other character in the pattern must be matched exactly. X X To suppress the special syntactic significance of any of `[]*?^-\', X and match the character exactly, precede it with a `\'. X X If DOT_SPECIAL is nonzero, X `*' and `?' do not match `.' at the beginning of TEXT. */ X Xint Xglob_match (pattern, text, dot_special) X char *pattern, *text; X int dot_special; X{ X register char *p = pattern, *t = text; X register char c; X X while ((c = *p++)) X { X switch (c) X { X case '?': X if (*t == 0 || (dot_special && t == text && *t == '.')) return 0; X else ++t; X break; X X case '\\': X if (*p++ != *t++) return 0; X break; X X case '*': X if (dot_special && t == text && *t == '.') X return 0; X return star_glob_match (p, t); X X case '[': X { X register char c1 = *t++; X register int invert = (*p == '^'); X X if (invert) p++; X X c = *p++; X while (1) X { X register char cstart = c, cend = c; X X if (c == '\\') X { X cstart = *p++; cend = cstart; X } X c = *p++; X if (c == '-') X { cend = *p++; if (cend == '\\') cend = *p++; c = *p++; } X if (c1 >= cstart && c1 <= cend) goto match; X if (c == ']') X break; X } X if (!invert) return 0; X break; X X match: X /* Skip the rest of the [...] construct that already matched. */ X while (c != ']') X { X c = *p++; X if (c == '\\') p++; X } X if (invert) return 0; X break; X } X X default: X if (c != *t++) return 0; X } X } X X if (*t) return 0; X return 1; X} X X/* Like glob_match, but match PATTERN against any final segment of TEXT. */ X Xstatic int Xstar_glob_match (pattern, text) X char *pattern, *text; X{ X register char *p = pattern, *t = text; X register char c, c1; X X while ((c = *p++) == '?' || c == '*') X { X if (c == '?' && *t++ == 0) X return 0; X } X X if (c == 0) X return 1; X X if (c == '\\') c1 = *p; X else c1 = c; X X for (;;) X { X if ((c == '[' || *t == c1) X && glob_match (p - 1, t, 0)) X return 1; X if (*t++ == 0) return 0; X } X} END_OF_FILE if test 7660 -ne `wc -c <'perms/glob_match.c'`; then echo shar: \"'perms/glob_match.c'\" unpacked with wrong size! fi # end of 'perms/glob_match.c' fi if test -f 'perms/perms.y' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'perms/perms.y'\" else echo shar: Extracting \"'perms/perms.y'\" \(7791 characters\) sed "s/^X//" >'perms/perms.y' <<'END_OF_FILE' X/* Copyright (c) 1990 Theo de Raadt deraadt@cpsc.ucalgary.ca X * All rights reserved. X * X * Redistribution and use in source and binary forms are permitted X * provided that the above copyright notice and this paragraph are X * duplicated in all such forms and that any documentation, X * advertising materials, and other materials related to such X * distribution and use acknowledge that the software was developed X * by Theo de Raadt. X */ X%{ X#ifndef lint Xchar Copyright[] = X"@(#) Copyright (c) 1990 Theo de Raadt.\nAll rights reserved.\n"; X#endif not lint X X#ifndef lint Xstatic char Sccsid[] = "@(#)perms.y 1.0 90/11/01 TDR"; X#endif not lint X X#include <sys/param.h> X#include <sys/types.h> X#include <sys/socket.h> X#include <sys/file.h> X#include <netinet/in.h> X#include <stdio.h> X#include <ctype.h> X#include <string.h> X#include <pwd.h> X#include <grp.h> X#include <rpc/types.h> X#include <rpc/rpc.h> X#include <rpcsvc/ypclnt.h> X#include <rpcsvc/yp_prot.h> X#include <syslog.h> X#include "y.tab.h" X X#undef DEBUG X X/* define SECURE if you want logins disallowed if errors show up X * during a map lookup. If this is not set, YP failures, incorrect X * maps, automount failure, etc.,will let anymore login until the X * problem is fixed. In general, you never want to define this! X */ X#undef SECURE X X#define SEARCHMAP "permissions" X X#define LX_SP 0x00 X#define LX_EOF 0x01 X#define LX_C 0x02 X#define LX_X 0x04 X#define LX_SC 0x08 X#define LX_S1 0x10 Xstatic char lookup[] = { X 0x01, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, /* 00-07 */ X 0x04, 0x00, 0x01, 0x04, 0x04, 0x01, 0x04, 0x04, /* 08-0f */ X 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, /* 10-17 */ X 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, /* 18-1f */ X 0x00, 0x02, 0x04, 0x04, 0x02, 0x04, 0x02, 0x04, /* 20-27 */ X 0x18, 0x18, 0x18, 0x02, 0x02, 0x0a, 0x18, 0x18, /* 28-2f */ X 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, /* 30-37 */ X 0x18, 0x18, 0x02, 0x04, 0x04, 0x04, 0x04, 0x18, /* 38-3f */ X 0x02, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, /* 40-47 */ X 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, /* 48-4f */ X 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, /* 50-57 */ X 0x18, 0x18, 0x18, 0x18, 0x04, 0x18, 0x18, 0x18, /* 58-5f */ X 0x04, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, /* 60-67 */ X 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, /* 68-6f */ X 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, /* 70-77 */ X 0x18, 0x18, 0x18, 0x04, 0x02, 0x04, 0x04, 0x04, /* 78-7f */ X}; X X#define YYSTYPE caddr_t Xextern YYSTYPE yylval; X Xstatic char *grplst[NGROUPS], **grplist; Xchar domain[MAXHOSTNAMELEN], key[MAXHOSTNAMELEN]; Xstatic char *usern, *ttyn, *line; Xstatic int ttymatch, grpusrmatch; X Xstatic int allow, err_allow; Xstatic char *stack[20]; Xstatic int stackp; X Xstatic Xyyerror() { X syslog(LOG_CRIT, X "permissions: [key %s] parsing error\n", key); X err_allow = 1; X} X X/* X * noisy, specifies to be noisy on failure or not X */ Xstatic char * Xgetypent(s, noisy) Xchar *s; X{ X char *entry; X int entrylen, err; X X err = yp_match(domain, SEARCHMAP, s, strlen(s), &entry, &entrylen); X if(err) { X if(noisy) syslog(LOG_CRIT, X "yperr: [key %s] %s\n", s, yperr_string(err)); X return NULL; X } X return entry; X} X X/* usr: user name. Absolutely has to be the login name. X * tty: tty name. if NULL, any tty will match. X * grps: NULL terminated array of group names. If grps==NULL, perms X * will fetch the groups using getpwent() and getgrent(). These X * have static data -- beware. X * lkey: base lookup key. If NULL, hostname will be used. X * X * return values need cleaning up. X * 1 - allowed X * 0 - not allowed X * -1 - error X */ Xint Xpermcheck(usr, tty, grps, lkey) Xchar *usr, *tty, **grps, *lkey; X{ X struct passwd *pwd; X struct group *grp; X int ngrps = 0; X X if(!usr) X return -1; X if(!grps) { X grps = grplst; X#ifdef DEBUG X printf("user: %s\n", usr); X#endif X setpwent(); X if( !(pwd=getpwnam(usr))) X return -1; X#ifdef DEBUG X printf("user: (%s)\n", pwd->pw_name); X#endif X X setgrent(); X if( !(grp=getgrgid(pwd->pw_gid)) ) X return -1; X *grps++ = strdup(grp->gr_name); X#ifdef DEBUG X printf("group: %s\n", grp->gr_name); X#endif X ngrps++; X while( grp=getgrent() ) { X if(pwd->pw_gid == grp->gr_gid) X continue; X while(*grp->gr_mem) { X if(!strcmp(*grp->gr_mem, usr)) { X if(++ngrps>NGROUPS) X break; X *grps++ = strdup(grp->gr_name); X#ifdef DEBUG X printf("group: %s\n", grp->gr_name); X#endif X } X grp->gr_mem++; X } X } X endgrent(); X endpwent(); X *grps = NULL; X grps = grplst; X } X if(lkey) X strcpy(key, lkey); X else X gethostname(key, sizeof key); X X getdomainname(domain, sizeof domain); X if( !(line=getypent(key, 0)) ) { X line = getypent("*", 1); X } X allow = 0; X err_allow = !line; X X if(line) { X usern = usr; X ttyn = tty; X grplist = grps; X ttymatch = grpusrmatch = -1; X yyparse(); X } X X#ifdef SECURE X return allow; X#else X return allow | err_allow; X#endif X} X Xstatic Xnewmap(s) Xchar *s; X{ X#ifdef DEBUG X printf("include %s, pushing %s", s, line); X#endif X stack[stackp++] = line; X if(stackp==sizeof(stack)/sizeof(char *)) { X syslog(LOG_CRIT, X "permissions: stack overflow on [key %s]\n", s); X line = stack[--stackp]; X err_allow = 1; X return; X } X line = getypent(s,1); X if(!line) { X syslog(LOG_CRIT, X "permissions: [key %s] not found\n", s); X line = stack[--stackp]; X err_allow = 1; X return; X } X#ifdef DEBUG X printf("result %s", line); X#endif X} X Xstatic Xyylex() X{ X static pos = 0; X static char savebuf[1024], *p; X char c; X Xrestartlex: X p = savebuf; X while(1) X switch( lookup[(c= *line++)] ) { X case LX_SP: X break; X case LX_EOF: X if(!stackp) X return -1; X line = stack[--stackp]; X#ifdef DEBUG X printf("popping %s", line); X#endif X goto restartlex; X case LX_C: X case LX_C|LX_SC: X#ifdef DEBUG X printf("lex: char '%c'\n", c); X#endif X return c; X case LX_X: X syslog(LOG_CRIT, X "permissions: [key %s] illegal char 0%3o\n", X key, c); X err_allow = 1; X return -1; X case LX_S1: X case LX_S1|LX_SC: X do { X *p++ = c; X c = *line++; X } while( lookup[c]&LX_SC ); X *p = '\0'; X line--; X yylval = savebuf; X#ifdef DEBUG X printf("lex: symbol %s\n", savebuf); X#endif X return SYMBOL; X } X} X Xstatic void Xgrpcheck(s, add) Xchar *s; X{ X FILE *fin; X char **grp, *p, buf[80]; X int i; X X switch(*s) { X case '(': X if( strchr(s+1, '(')) { X syslog(LOG_CRIT, X "permissions: [key %s] can't nest brackets\n", s); X return; X } X X p = strchr(s, ')'); X if(p) X *p = '\0'; X else { X syslog(LOG_CRIT, X "permissions: [key %s] include syntax error\n", s); X return; X } X if( strchr(s, ')')) { X syslog(LOG_CRIT, X "permissions: [key %s] can't nest brackets\n", s); X return; X } X X s++; X fin = fopen(s, "r"); X if(!fin) { X syslog(LOG_CRIT, X "permissions: [key %s] can't open include\n", s); X return; X } X while( fgets(buf, sizeof buf, fin) ) { X for(p=buf; *p; p++) X if( *p==' ' || *p=='\n' || *p=='#' || *p=='\t' ) { X *p = '\0'; X break; X } X if(!*buf) X continue; X#ifdef DEBUG X printf("file: %s '%s'\n", s, buf); X#endif X grpcheck(buf, add); X } X fclose(fin); X break; X case '.': X grp = grplist; X while(*grp) { X if( glob_match(s+1, *grp, 0) ) X grpusrmatch = add; X grp++; X } X break; X default: X if( !strcmp(s, usern) ) X grpusrmatch = add; X break; X } X} X X%} X X%token SYMBOL X%start permlist X X%% Xpermlist : perm X | permlist '|' perm X ; X Xperm : ttylist ':' grouplist { X if(ttymatch!=-1 && grpusrmatch!=-1) X allow = ttymatch && grpusrmatch; X ttymatch = grpusrmatch = -1; X } X | '$' SYMBOL { newmap($2); } permlist X | X ; X Xttylist : tty X | ttylist ',' tty X ; Xgrouplist : group X | grouplist ',' group X ; X Xtty : SYMBOL { X if(!ttyn) X ttymatch = 1; X else if( glob_match($1, ttyn, 0) ) X ttymatch = 1; X } X ; X Xgroup : '+' SYMBOL { grpcheck($2, 1); } X | '-' SYMBOL { grpcheck($2, 0); } X ; X%% END_OF_FILE if test 7791 -ne `wc -c <'perms/perms.y'`; then echo shar: \"'perms/perms.y'\" unpacked with wrong size! fi # end of 'perms/perms.y' fi if test -f 'permtest/Makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'permtest/Makefile'\" else echo shar: Extracting \"'permtest/Makefile'\" \(164 characters\) sed "s/^X//" >'permtest/Makefile' <<'END_OF_FILE' XOBJ = permtest.o ../perms/perms.o ../perms/glob_match.o XCFLAGS = -g -DPERMS X Xpermtest: $(OBJ) X $(CC) $(LDFLAGS) $(OBJ) -o permtest X Xclean: X $(RM) *~ *.o permtest END_OF_FILE if test 164 -ne `wc -c <'permtest/Makefile'`; then echo shar: \"'permtest/Makefile'\" unpacked with wrong size! fi chmod +x 'permtest/Makefile' # end of 'permtest/Makefile' fi if test -f 'permtest/permtest.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'permtest/permtest.c'\" else echo shar: Extracting \"'permtest/permtest.c'\" \(1614 characters\) sed "s/^X//" >'permtest/permtest.c' <<'END_OF_FILE' X#include <sys/param.h> X#include <sys/types.h> X#include <sys/socket.h> X#include <string.h> X#include <stdio.h> X#include <ctype.h> X#include <netdb.h> X#include <grp.h> X#include <pwd.h> X Xchar *grpnames[NGROUPS+1]; Xint ngrps; Xstruct passwd *pwd; Xstruct group *grp; Xint verbose; X Xextern int permcheck(); X Xmain(argc, argv) Xchar **argv; X{ X char *logn, *ttyn, *hostn; X struct hostent *hent; X int lp, i; X X if(argc<4) { X fprintf(stderr, "usage: %s [-v] username ttyname hostname\n", X *argv); X exit(0); X } X if(!strcmp(argv[1], "-v")) { X argv++; X verbose=1; X } X X logn = argv[1]; X ttyn = argv[2]; X X setpwent(); X pwd = getpwnam(logn); X if(!pwd) { X fprintf(stderr, "%s: unknown user\n", logn); X exit(0); X } X X setgrent(); X ngrps = 0; X if(!(grp=getgrgid(pwd->pw_gid))) { X fprintf(stderr, X "%d: group id has no name\n", pwd->pw_gid); X exit(0); X } X grpnames[ngrps++] = strdup(grp->gr_name); X while( grp=getgrent() ) { X if(pwd->pw_gid == grp->gr_gid) X continue; X while(*grp->gr_mem) { X if( !strcmp(logn, *grp->gr_mem)) { X grpnames[ngrps++] = strdup(grp->gr_name); X } X grp->gr_mem++; X } X } X endgrent(); X grpnames[ngrps] = NULL; X X if(verbose) { X printf("%d group%s:", ngrps, (ngrps>1)?"s":""); X for(i=0; i<ngrps; i++) X printf(" %s", grpnames[i]); X printf("\n"); X } X X for( argv= &argv[3]; *argv; argv++) { X if((hent = gethostbyname(*argv))) X hostn = hent->h_name; X else X hostn = *argv; X lp = permcheck(logn, ttyn, grpnames, hostn); X if(verbose) X printf("user %s %spermitted on %s:%s\n", X logn, lp ? "":"not ", hostn, ttyn); X else X printf("%s: %s\n", hostn, lp ? "":"not"); X } X exit(0); X} X X X END_OF_FILE if test 1614 -ne `wc -c <'permtest/permtest.c'`; then echo shar: \"'permtest/permtest.c'\" unpacked with wrong size! fi # end of 'permtest/permtest.c' fi echo shar: End of shell archive. exit 0 -- SunOS 4.0.3: /usr/include/vm/as.h, Line 44 | Theo de Raadt SunOS 4.1.1: /usr/include/vm/as.h, Line 49 | deraadt@cpsc.ucalgary.ca Is it a typo? Should the '_' be an 's'?? :-) | deraadt@cpsc.ucalgary.ca