From 0f94b0c4d6f67ee6bd36a0d679396482c5689264 Mon Sep 17 00:00:00 2001 From: Ivan Rako Date: Wed, 20 May 2009 16:46:56 +0200 Subject: [PATCH] prva verzija za lenny --- Makefile | 33 ++ README.CARNet | 21 + changelog.CARNet | 1 + debian/changelog | 41 ++ debian/compat | 1 + debian/conffiles | 1 + debian/control | 16 + debian/dirs | 4 + debian/docs | 3 + debian/install | 3 + debian/postinst | 33 ++ debian/rules | 86 ++++ dqblk_rpc.h | 20 + dqblk_v1.h | 21 + dqblk_v2.h | 41 ++ dqblk_xfs.h | 25 + manual.txt | 1 + mntopt.h | 25 + quota.h | 128 +++++ quotaio.h | 59 +++ quotaio_generic.h | 24 + quotaio_v1.h | 49 ++ quotaio_v2.h | 101 ++++ quotaio_xfs.h | 150 ++++++ quotasys.h | 137 +++++ sysadm.man | 101 ++++ sysadmin.c | 1487 +++++++++++++++++++++++++++++++++++++++++++++++++++++ sysadmin.h | 138 +++++ sysadmin.html | 170 ++++++ test.c | 28 + version.h | 4 + 31 files changed, 2952 insertions(+) create mode 100644 Makefile create mode 100644 README.CARNet create mode 120000 changelog.CARNet create mode 100644 debian/changelog create mode 100644 debian/compat create mode 100644 debian/conffiles create mode 100644 debian/control create mode 100644 debian/dirs create mode 100644 debian/docs create mode 100644 debian/install create mode 100755 debian/postinst create mode 100755 debian/rules create mode 100644 dqblk_rpc.h create mode 100644 dqblk_v1.h create mode 100644 dqblk_v2.h create mode 100644 dqblk_xfs.h create mode 120000 manual.txt create mode 100644 mntopt.h create mode 100644 quota.h create mode 100644 quotaio.h create mode 100644 quotaio_generic.h create mode 100644 quotaio_v1.h create mode 100644 quotaio_v2.h create mode 100644 quotaio_xfs.h create mode 100644 quotasys.h create mode 100644 sysadm.man create mode 100644 sysadmin.c create mode 100644 sysadmin.h create mode 100644 sysadmin.html create mode 100644 test.c create mode 100644 users create mode 100644 version.h diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..ea48209 --- /dev/null +++ b/Makefile @@ -0,0 +1,33 @@ +# +# Makefile for sysadmin, 12 Mar 1997 +# CARNet System Admin Utility v1.24 +# +# Written by Zlatko Calusic +# SRCE, University Computing Centre, Croatia +# + +SHELL = /bin/sh +CC = gcc +COPTS = -s -O2 -Wall + +all: sysadmin.c sysadmin.h + @echo "CARNet System Admin Utility v1.26, 05 Apr 2002" + @echo "Written by Zlatko Calusic" + @echo "SRCE, University Computing Centre, Croatia" + @echo "CARNet, Croatian Academic and Research Network" + @echo "" + @echo "If you compile on Digital Unix V4.0, add -DDU4 -lsecurity!!!" + @echo "" + @rm -f sysadmin + env PROG_ENV=POSIX $(CC) $(COPTS) sysadmin.c -o sysadmin ### -DDU4 -lsecurity + +debug: sysadmin.c sysadmin.h + @rm -f sysadmin + env PROG_ENV=POSIX $(CC) -g -DDEBUG -Wall -Wno-implicit -Wstrict-prototypes -pedantic sysadmin.c -o sysadmin ### -DDU4 -lsecurity + +clean: + @rm -f sysadmin + rm -f *.o sysadmin core *~ + +love: + @echo "Not war!" diff --git a/README.CARNet b/README.CARNet new file mode 100644 index 0000000..b00abe5 --- /dev/null +++ b/README.CARNet @@ -0,0 +1,21 @@ +CARNet sysadmin +~~~~~~~~~~~~~~~ + +Ovo je CARNetov paket za pojednostavljeno baratanje osnovnim funkcijama +OS-a: dodavanje i brisanje korisnika, postavljanje quoti, i restartanje +sustava. Preko konfiguracijske datoteke /etc/sysadmin/users moguce je +razlicitim korisnicima omoguciti pokretanje i tako izbjeci koristenje +root ljuske za uobicajene zadatke. + +Program radi na Linuxu i Solarisu. U izvornom kodu postoje reference na +Digital Unix (sada Tru64) i cak Ultrix, ali nije provjereno rade li ti +dijelovi koda. + +Zapise o pokretanjima programa mozete naci u /var/log/sysadmin.log. + +Ukoliko zelite izbjeci provjeru ulogiravanja sa konzole, u datoteku +/etc/sysadmin/config upisite: + +no_console_check + +Zoran Dzelajlija , Sat, 6 Dec 2003 18:09:53 +0000 diff --git a/changelog.CARNet b/changelog.CARNet new file mode 120000 index 0000000..6a28af6 --- /dev/null +++ b/changelog.CARNet @@ -0,0 +1 @@ +changelog \ No newline at end of file diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..1051266 --- /dev/null +++ b/debian/changelog @@ -0,0 +1,41 @@ +sysadmin-cn (1.26.2) stable; urgency=low + + * Prva verzija za lenny + * deb-src package + + -- Ivan Rako Wed, 20 May 2009 13:38:25 +0200 + +sysadmin (1.26-1) testing unstable; urgency=low + + * Dignuta Debian revizija da bi radio upgrade sa woodyja. + + -- Zoran Dzelajlija Sat, 21 Feb 2004 00:55:47 +0100 + +sysadmin (1.26) unstable; urgency=low + + * Quota na Linuxu: + + bez podrske za image mountane sa -o loop, samo pravi device. + * Opcija za izbjegavanje provjere konzole. + + -- Zoran Dzelajlija Sat, 6 Dec 2003 15:18:53 +0100 + +sysadmin (1.25.1) stable unstable; urgency=low + + * If /etc/default/useradd exists, don't force shell (Linux). + + -- Zoran Dzelajlija Fri, 30 May 2003 11:36:11 +0200 + +sysadmin (1.25-1) testing unstable; urgency=low + + * Renamed package to sysadmin-cn. + + -- Zoran Dzelajlija Mon, 29 Apr 2002 16:10:12 +0200 + +sysadmin (1.25) testing unstable; urgency=low + + * First linux release. + * Linux port has no quota support. + * Maybe fixed race condition with useradd and passwd on Linux? + + -- Zoran Dzelajlija Sun, 28 Apr 2002 21:27:28 +0200 + diff --git a/debian/compat b/debian/compat new file mode 100644 index 0000000..b8626c4 --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +4 diff --git a/debian/conffiles b/debian/conffiles new file mode 100644 index 0000000..bdb6438 --- /dev/null +++ b/debian/conffiles @@ -0,0 +1 @@ +etc/sysadmin/users diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..a9972ef --- /dev/null +++ b/debian/control @@ -0,0 +1,16 @@ +Source: sysadmin-cn +Section: admin +Priority: optional +Maintainer: Ivan Rako +Build-Depends: debhelper (>= 4) +Standards-Version: 3.6.1.0 + +Package: sysadmin-cn +Replaces: sysadmin +Conflicts: sysadmin +Provides: sysadmin +Depends: libc6, quota (>= 3.09) +Architecture: any +Description: tty-based system administration tool. + sysadmin is a simple menu driven tool for usual system administration + tasks, including user and group management and system shutdown. diff --git a/debian/dirs b/debian/dirs new file mode 100644 index 0000000..e1c0b76 --- /dev/null +++ b/debian/dirs @@ -0,0 +1,4 @@ +etc/sysadmin +usr/bin +usr/share/sysadmin +var/log diff --git a/debian/docs b/debian/docs new file mode 100644 index 0000000..aa4064e --- /dev/null +++ b/debian/docs @@ -0,0 +1,3 @@ +README.CARNet +changelog.CARNet +manual.txt diff --git a/debian/install b/debian/install new file mode 100644 index 0000000..0db8436 --- /dev/null +++ b/debian/install @@ -0,0 +1,3 @@ +users etc/sysadmin +sysadm.man usr/share/sysadmin +sysadmin usr/bin diff --git a/debian/postinst b/debian/postinst new file mode 100755 index 0000000..c43bc52 --- /dev/null +++ b/debian/postinst @@ -0,0 +1,33 @@ +#!/bin/sh -e + +PATH=/bin:/usr/bin:/sbin:/usr/sbin +CONFIG=/etc/sysadmin/users +OLDCONFIG=/etc/adminusers +LOG=/var/log/sysadmin.log +OLDLOG=/var/adm/adminlog + +if [ "$1" == "configure" ]; then + + if [ "$2" ] && dpkg --compare-versions "$2" le "1.24" ; then + echo "" + echo "CN: Warning: configuration files have moved since 1.24!" + echo "CN: DO read /usr/share/doc/sysadmin-cn/README.CARNet for details." + fi + + # Move files to right places. + if [ -f $OLDCONFIG ]; then + mv $OLDCONFIG $CONFIG + echo "CN: Moved $OLDCONFIG to $CONFIG." + fi + if [ -f $OLDLOG ]; then + mv $OLDLOG $LOG + echo "CN: moved $OLDLOG to $LOG." + fi + + # Create users file if none exists. + if [ ! -e $CONFIG ]; then + touch $CONFIG + chmod 600 $CONFIG + fi + +fi diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..7e32f42 --- /dev/null +++ b/debian/rules @@ -0,0 +1,86 @@ +#!/usr/bin/make -f +# -*- makefile -*- +# Sample debian/rules that uses debhelper. +# This file was originally written by Joey Hess and Craig Small. +# As a special exception, when this file is copied by dh-make into a +# dh-make output file, you may use that output file without restriction. +# This special exception was added by Craig Small in version 0.37 of dh-make. + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +configure: configure-stamp +configure-stamp: + dh_testdir + # Add here commands to configure the package. + + touch configure-stamp + + +build: build-stamp + +build-stamp: configure-stamp + dh_testdir + + # Add here commands to compile the package. + $(MAKE) + + touch build-stamp + +clean: + dh_testdir + dh_testroot + rm -f build-stamp configure-stamp + + # Add here commands to clean up after the build process. + -$(MAKE) clean + + dh_clean + +install: build + dh_testdir + dh_testroot + dh_clean -k + dh_installdirs + + # Add here commands to install the package into debian/openssh-cn. + # $(MAKE) install DESTDIR=$(CURDIR)/debian/openssh-cn + + +# Build architecture-independent files here. +binary-indep: build install +# We have nothing to do by default. + +# Build architecture-dependent files here. +binary-arch: build install + dh_testdir + dh_testroot + dh_installchangelogs -k + dh_installdocs +# dh_installexamples + dh_install +# dh_installmenu +# dh_installdebconf +# dh_installlogrotate +# dh_installemacsen +# dh_installpam +# dh_installmime +# dh_installinit +# dh_installcron +# dh_installinfo + dh_installman +# dh_link + dh_strip +# dh_compress + dh_fixperms +# dh_perl +# dh_python + dh_shlibdeps + dh_gencontrol + dh_makeshlibs + dh_installdeb + dh_md5sums + dh_builddeb + +binary: binary-indep binary-arch +.PHONY: build clean binary-indep binary-arch binary install configure diff --git a/dqblk_rpc.h b/dqblk_rpc.h new file mode 100644 index 0000000..f5a666a --- /dev/null +++ b/dqblk_rpc.h @@ -0,0 +1,20 @@ +/* + * Headerfile for rpc quotafile format + */ + +#ifndef _DQBLK_RPC_H +#define _DQBLK_RPC_H + +/* Values used for communication through network */ +#define Q_RPC_GETQUOTA 0x0300 /* get limits and usage */ +#define Q_RPC_SETQUOTA 0x0400 /* set limits and usage */ +#define Q_RPC_SETUSE 0x0500 /* set usage */ +#define Q_RPC_SETQLIM 0x0700 /* set limits */ + +#define RPC_DQBLK_SIZE_BITS 10 +#define RPC_DQBLK_SIZE (1 << RPC_DQBLK_SIZE_BITS) + +/* Operations above this format */ +extern struct quotafile_ops quotafile_ops_rpc; + +#endif diff --git a/dqblk_v1.h b/dqblk_v1.h new file mode 100644 index 0000000..fe3d683 --- /dev/null +++ b/dqblk_v1.h @@ -0,0 +1,21 @@ +/* + * Headerfile for old quotafile format + */ + +#ifndef _DQBLK_V1_H +#define _DQBLK_V1_H + +/* Values of quota calls */ +#define Q_V1_RSQUASH 0x1000 +#define Q_V1_GETQUOTA 0x300 +#define Q_V1_SETQUOTA 0x400 +#define Q_V1_SETUSE 0x500 +#define Q_V1_SETQLIM 0x700 +#define Q_V1_GETSTATS 0x800 + +struct quotafile_ops; /* Will be defined later in quotaio.h */ + +/* Operations above this format */ +extern struct quotafile_ops quotafile_ops_1; + +#endif diff --git a/dqblk_v2.h b/dqblk_v2.h new file mode 100644 index 0000000..c5932b3 --- /dev/null +++ b/dqblk_v2.h @@ -0,0 +1,41 @@ +/* + * + * Header file for disk format of new quotafile format + * + */ + +#ifndef _DQBLK_V2_H +#define _DQBLK_V2_H + +#include + +#define Q_V2_GETQUOTA 0x0D00 /* Get limits and usage */ +#define Q_V2_SETQUOTA 0x0E00 /* Set limits and usage */ +#define Q_V2_SETUSE 0x0F00 /* Set only usage */ +#define Q_V2_SETQLIM 0x0700 /* Set only limits */ +#define Q_V2_GETINFO 0x0900 /* Get information about quota */ +#define Q_V2_SETINFO 0x0A00 /* Set information about quota */ +#define Q_V2_SETGRACE 0x0B00 /* Set just grace times in quotafile information */ +#define Q_V2_SETFLAGS 0x0C00 /* Set just flags in quotafile information */ +#define Q_V2_GETSTATS 0x1100 /* get collected stats (before proc was used) */ + +/* Structure for format specific information */ +struct v2_mem_dqinfo { + uint dqi_flags; /* Flags set in quotafile */ + uint dqi_blocks; /* Number of blocks in file */ + uint dqi_free_blk; /* Number of first free block in the list */ + uint dqi_free_entry; /* Number of first block with free entry in the list */ + uint dqi_used_entries; /* Number of entries in file - updated by scan_dquots */ + uint dqi_data_blocks; /* Number of data blocks in file - updated by scan_dquots */ +}; + +struct v2_mem_dqblk { + loff_t dqb_off; /* Offset of dquot in file */ +}; + +struct quotafile_ops; /* Will be defined later in quotaio.h */ + +/* Operations above this format */ +extern struct quotafile_ops quotafile_ops_2; + +#endif diff --git a/dqblk_xfs.h b/dqblk_xfs.h new file mode 100644 index 0000000..8b03d98 --- /dev/null +++ b/dqblk_xfs.h @@ -0,0 +1,25 @@ +/* + * Headerfile for XFS quota format + */ + +#ifndef _DQBLK_XFS_H +#define _DQBLK_XFS_H + +#include "quotaio_xfs.h" + +#define Q_XFS_QUOTAON Q_XQUOTAON +#define Q_XFS_QUOTAOFF Q_XQUOTAOFF +#define Q_XFS_GETQUOTA Q_XGETQUOTA +#define Q_XFS_SETQLIM Q_XSETQLIM +#define Q_XFS_GETQSTAT Q_XGETQSTAT +#define Q_XFS_QUOTARM Q_XQUOTARM + +#define xfs_mem_dqinfo fs_quota_stat +#define xfs_kern_dqblk fs_disk_quota + +struct quotafile_ops; /* Will be defined later in quotaio.h */ + +/* Operations above this format */ +extern struct quotafile_ops quotafile_ops_xfs; + +#endif diff --git a/manual.txt b/manual.txt new file mode 120000 index 0000000..64ca5ac --- /dev/null +++ b/manual.txt @@ -0,0 +1 @@ +../../sysadmin/sysadm.man \ No newline at end of file diff --git a/mntopt.h b/mntopt.h new file mode 100644 index 0000000..81f023c --- /dev/null +++ b/mntopt.h @@ -0,0 +1,25 @@ +#ifndef _MNTOPT_H +#define _MNTOPT_H + +#include + +/* filesystem type */ +#define MNTTYPE_EXT2 "ext2" /* 2nd Extended file system */ +#define MNTTYPE_EXT3 "ext3" /* ext2 + journaling */ +#define MNTTYPE_MINIX "minix" /* MINIX file system */ +#define MNTTYPE_UFS "ufs" /* UNIX file system */ +#define MNTTYPE_UDF "udf" /* OSTA UDF file system */ +#define MNTTYPE_REISER "reiserfs" /* Reiser file system */ +#define MNTTYPE_XFS "xfs" /* SGI XFS file system */ +#define MNTTYPE_AUTOFS "autofs" /* Automount mountpoint */ + +/* mount options */ +#define MNTOPT_NOQUOTA "noquota" /* don't enforce quota */ +#define MNTOPT_QUOTA "quota" /* enforce user quota */ +#define MNTOPT_USRQUOTA "usrquota" /* enforce user quota */ +#define MNTOPT_GRPQUOTA "grpquota" /* enforce group quota */ +#define MNTOPT_RSQUASH "rsquash" /* root as ordinary user */ +#define MNTOPT_BIND "bind" /* binded mount */ +#define MNTOPT_LOOP "loop" /* loopback mount */ + +#endif diff --git a/quota.h b/quota.h new file mode 100644 index 0000000..a39a9ae --- /dev/null +++ b/quota.h @@ -0,0 +1,128 @@ +#ifndef _QUOTA_H +#define _QUOTA_H + +#include + +typedef u_int32_t qid_t; /* Type in which we store ids in memory */ +typedef u_int64_t qsize_t; /* Type in which we store size limitations */ + +#define MAXQUOTAS 2 +#define USRQUOTA 0 /* element used for user quotas */ +#define GRPQUOTA 1 /* element used for group quotas */ + +/* + * Definitions for the default names of the quotas files. + */ +#define INITQFNAMES { \ + "user", /* USRQUOTA */ \ + "group", /* GRPQUOTA */ \ + "undefined", \ +} + +/* + * Definitions of magics and versions of current quota files + */ +#define INITQMAGICS {\ + 0xd9c01f11, /* USRQUOTA */\ + 0xd9c01927 /* GRPQUOTA */\ +} + +/* Size of blocks in which are counted size limits in generic utility parts */ +#define QUOTABLOCK_BITS 10 +#define QUOTABLOCK_SIZE (1 << QUOTABLOCK_BITS) + +/* Conversion routines from and to quota blocks */ +#define qb2kb(x) ((x) << (QUOTABLOCK_BITS-10)) +#define kb2qb(x) ((x) >> (QUOTABLOCK_BITS-10)) +#define toqb(x) (((x) + QUOTABLOCK_SIZE - 1) >> QUOTABLOCK_BITS) + +/* + * Command definitions for the 'quotactl' system call. + * The commands are broken into a main command defined below + * and a subcommand that is used to convey the type of + * quota that is being manipulated (see above). + */ +#define SUBCMDMASK 0x00ff +#define SUBCMDSHIFT 8 +#define QCMD(cmd, type) (((cmd) << SUBCMDSHIFT) | ((type) & SUBCMDMASK)) + +#define Q_6_5_QUOTAON 0x0100 /* enable quotas */ +#define Q_6_5_QUOTAOFF 0x0200 /* disable quotas */ +#define Q_6_5_SYNC 0x0600 /* sync disk copy of a filesystems quotas */ + +#define Q_SYNC 0x800001 /* sync disk copy of a filesystems quotas */ +#define Q_QUOTAON 0x800002 /* turn quotas on */ +#define Q_QUOTAOFF 0x800003 /* turn quotas off */ +#define Q_GETFMT 0x800004 /* get quota format used on given filesystem */ +#define Q_GETINFO 0x800005 /* get information about quota files */ +#define Q_SETINFO 0x800006 /* set information about quota files */ +#define Q_GETQUOTA 0x800007 /* get user quota structure */ +#define Q_SETQUOTA 0x800008 /* set user quota structure */ + +/* + * Quota structure used for communication with userspace via quotactl + * Following flags are used to specify which fields are valid + */ +#define QIF_BLIMITS 1 +#define QIF_SPACE 2 +#define QIF_ILIMITS 4 +#define QIF_INODES 8 +#define QIF_BTIME 16 +#define QIF_ITIME 32 +#define QIF_LIMITS (QIF_BLIMITS | QIF_ILIMITS) +#define QIF_USAGE (QIF_SPACE | QIF_INODES) +#define QIF_TIMES (QIF_BTIME | QIF_ITIME) +#define QIF_ALL (QIF_LIMITS | QIF_USAGE | QIF_TIMES) + +struct if_dqblk { + u_int64_t dqb_bhardlimit; + u_int64_t dqb_bsoftlimit; + u_int64_t dqb_curspace; + u_int64_t dqb_ihardlimit; + u_int64_t dqb_isoftlimit; + u_int64_t dqb_curinodes; + u_int64_t dqb_btime; + u_int64_t dqb_itime; + u_int32_t dqb_valid; +}; + +/* + * Structure used for setting quota information about file via quotactl + * Following flags are used to specify which fields are valid + */ +#define IIF_BGRACE 1 +#define IIF_IGRACE 2 +#define IIF_FLAGS 4 +#define IIF_ALL (IIF_BGRACE | IIF_IGRACE | IIF_FLAGS) + +struct if_dqinfo { + u_int64_t dqi_bgrace; + u_int64_t dqi_igrace; + u_int32_t dqi_flags; + u_int32_t dqi_valid; +}; + +/* Quota format identifiers */ +#define QFMT_VFS_OLD 1 +#define QFMT_VFS_V0 2 + +/* Flags supported by kernel */ +#define V1_DQF_RSQUASH 1 + +/* Ioctl for getting quota size */ +#include +#ifndef FIOQSIZE + #if defined(__alpha__) || defined(__powerpc__) || defined(__sh__) || defined(__sparc__) || defined(__sparc64__) + #define FIOQSIZE _IOR('f', 128, loff_t) + #elif defined(__arm__) || defined(__mc68000__) || defined(__s390__) + #define FIOQSIZE 0x545E + #elif defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__ia64__) || defined(__parisc__) || defined(__cris__) || defined(__hppa__) + #define FIOQSIZE 0x5460 + #elif defined(__mips__) || defined(__mips64__) + #define FIOQSIZE 0x6667 + #endif +#endif + +long quotactl __P((int, const char *, qid_t, caddr_t)); + +#endif /* _QUOTA_ */ diff --git a/quotaio.h b/quotaio.h new file mode 100644 index 0000000..7216156 --- /dev/null +++ b/quotaio.h @@ -0,0 +1,59 @@ +/* + * + * Header of IO operations for quota utilities + * + */ + +#ifndef _QUOTAIO_H +#define _QUOTAIO_H + +#include +#include +#include + +#include "quota.h" + +/* Latest known versions */ +#define INITKNOWNVERSIONS {\ + 0,\ + 0\ +} + +#define QUOTAFORMATS 4 + +#define INITQFBASENAMES {\ + "quota",\ + "aquota",\ + "",\ + ""\ +} + +#define INITQFMTNAMES {\ + "vfsold",\ + "vfsv0",\ + "rpc",\ + "xfs"\ +} + +/* Values for format handling */ +#define QF_UNKNOWN -3 /* Format cannot be detected from filename */ +#define QF_TOONEW -2 /* Quota format is too new to handle */ +#define QF_ERROR -1 /* There was error while detecting format (maybe unknown format...) */ +#define QF_VFSOLD 0 /* Old quota format */ +#define QF_VFSV0 1 /* New quota format - version 0 */ +#define QF_RPC 2 /* RPC should be used on given filesystem */ +#define QF_XFS 3 /* XFS quota format */ + +/* + * Definitions for disk quotas imposed on the average user + * (big brother finally hits Linux). + * + * The following constants define the default amount of time given a user + * before the soft limits are treated as hard limits (usually resulting + * in an allocation failure). The timer is started when the user crosses + * their soft limit, it is reset when they go below their soft limit. + */ +#define MAX_IQ_TIME 604800 /* (7*24*60*60) 1 week */ +#define MAX_DQ_TIME 604800 /* (7*24*60*60) 1 week */ + +#endif /* _QUOTAIO_H */ diff --git a/quotaio_generic.h b/quotaio_generic.h new file mode 100644 index 0000000..47d36a8 --- /dev/null +++ b/quotaio_generic.h @@ -0,0 +1,24 @@ +/* + * + * Header file for communication with kernel generic interface + * + */ + +#ifndef _QUOTAIO_GENERIC_H +#define _QUOTAIO_GENERIC_H + +#include "quotaio.h" + +/* Get info from kernel to handle */ +int vfs_get_info(struct quota_handle *h); + +/* Set info in kernel from handle */ +int vfs_set_info(struct quota_handle *h, int flags); + +/* Get dquot from kernel */ +int vfs_get_dquot(struct dquot *dquot); + +/* Set dquot in kernel */ +int vfs_set_dquot(struct dquot *dquot, int flags); + +#endif diff --git a/quotaio_v1.h b/quotaio_v1.h new file mode 100644 index 0000000..aa9448e --- /dev/null +++ b/quotaio_v1.h @@ -0,0 +1,49 @@ +/* + * Headerfile for old quotafile format + */ + +#ifndef _QUOTAIO_V1_H +#define _QUOTAIO_V1_H + +#include + +#define V1_DQBLK_SIZE_BITS 10 +#define V1_DQBLK_SIZE (1 << V1_DQBLK_SIZE_BITS) /* Size of one quota block in bytes in old format */ + +#define V1_DQOFF(__id) ((loff_t) ((__id) * sizeof(struct v1_disk_dqblk))) + +/* Structure of quota on disk */ +struct v1_disk_dqblk { + u_int32_t dqb_bhardlimit; /* absolute limit on disk blks alloc */ + u_int32_t dqb_bsoftlimit; /* preferred limit on disk blks */ + u_int32_t dqb_curblocks; /* current block count */ + u_int32_t dqb_ihardlimit; /* maximum # allocated inodes */ + u_int32_t dqb_isoftlimit; /* preferred limit on inodes */ + u_int32_t dqb_curinodes; /* current # allocated inodes */ + time_t dqb_btime; /* time limit for excessive disk use */ + time_t dqb_itime; /* time limit for excessive files */ +} __attribute__ ((packed)); + +/* Structure used for communication with kernel */ +struct v1_kern_dqblk { + u_int32_t dqb_bhardlimit; /* absolute limit on disk blks alloc */ + u_int32_t dqb_bsoftlimit; /* preferred limit on disk blks */ + u_int32_t dqb_curblocks; /* current block count */ + u_int32_t dqb_ihardlimit; /* maximum # allocated inodes */ + u_int32_t dqb_isoftlimit; /* preferred inode limit */ + u_int32_t dqb_curinodes; /* current # allocated inodes */ + time_t dqb_btime; /* time limit for excessive disk use */ + time_t dqb_itime; /* time limit for excessive files */ +}; + +struct v1_dqstats { + u_int32_t lookups; + u_int32_t drops; + u_int32_t reads; + u_int32_t writes; + u_int32_t cache_hits; + u_int32_t allocated_dquots; + u_int32_t free_dquots; + u_int32_t syncs; +}; +#endif diff --git a/quotaio_v2.h b/quotaio_v2.h new file mode 100644 index 0000000..2482156 --- /dev/null +++ b/quotaio_v2.h @@ -0,0 +1,101 @@ +/* + * + * Header file for disk format of new quotafile format + * + */ + +#ifndef _QUOTAIO_V2_H +#define _QUOTAIO_V2_H + +#include +#include "quota.h" + +#define V2_DQINFOOFF sizeof(struct v2_disk_dqheader) /* Offset of info header in file */ +#define V2_DQBLKSIZE_BITS 10 +#define V2_DQBLKSIZE (1 << V2_DQBLKSIZE_BITS) /* Size of block with quota structures */ +#define V2_DQTREEOFF 1 /* Offset of tree in file in blocks */ +#define V2_DQTREEDEPTH 4 /* Depth of quota tree */ +#define V2_DQSTRINBLK ((V2_DQBLKSIZE - sizeof(struct v2_disk_dqdbheader)) / sizeof(struct v2_disk_dqblk)) /* Number of entries in one blocks */ +#define V2_GETIDINDEX(id, depth) (((id) >> ((V2_DQTREEDEPTH-(depth)-1)*8)) & 0xff) +#define V2_GETENTRIES(buf) ((struct v2_disk_dqblk *)(((char *)(buf)) + sizeof(struct v2_disk_dqdbheader))) +#define INIT_V2_VERSIONS { 0, 0} + +struct v2_disk_dqheader { + u_int32_t dqh_magic; /* Magic number identifying file */ + u_int32_t dqh_version; /* File version */ +} __attribute__ ((packed)); + +/* Flags for version specific files */ +#define V2_DQF_MASK 0x0000 /* Mask for all valid ondisk flags */ + +/* Header with type and version specific information */ +struct v2_disk_dqinfo { + u_int32_t dqi_bgrace; /* Time before block soft limit becomes hard limit */ + u_int32_t dqi_igrace; /* Time before inode soft limit becomes hard limit */ + u_int32_t dqi_flags; /* Flags for quotafile (DQF_*) */ + u_int32_t dqi_blocks; /* Number of blocks in file */ + u_int32_t dqi_free_blk; /* Number of first free block in the list */ + u_int32_t dqi_free_entry; /* Number of block with at least one free entry */ +} __attribute__ ((packed)); + +/* + * Structure of header of block with quota structures. It is padded to 16 bytes so + * there will be space for exactly 18 quota-entries in a block + */ +struct v2_disk_dqdbheader { + u_int32_t dqdh_next_free; /* Number of next block with free entry */ + u_int32_t dqdh_prev_free; /* Number of previous block with free entry */ + u_int16_t dqdh_entries; /* Number of valid entries in block */ + u_int16_t dqdh_pad1; + u_int32_t dqdh_pad2; +} __attribute__ ((packed)); + +/* Structure of quota for one user on disk */ +struct v2_disk_dqblk { + u_int32_t dqb_id; /* id this quota applies to */ + u_int32_t dqb_ihardlimit; /* absolute limit on allocated inodes */ + u_int32_t dqb_isoftlimit; /* preferred inode limit */ + u_int32_t dqb_curinodes; /* current # allocated inodes */ + u_int32_t dqb_bhardlimit; /* absolute limit on disk space (in QUOTABLOCK_SIZE) */ + u_int32_t dqb_bsoftlimit; /* preferred limit on disk space (in QUOTABLOCK_SIZE) */ + u_int64_t dqb_curspace; /* current space occupied (in bytes) */ + u_int64_t dqb_btime; /* time limit for excessive disk use */ + u_int64_t dqb_itime; /* time limit for excessive inode use */ +} __attribute__ ((packed)); + +/* Structure of quota for communication with kernel */ +struct v2_kern_dqblk { + unsigned int dqb_ihardlimit; + unsigned int dqb_isoftlimit; + unsigned int dqb_curinodes; + unsigned int dqb_bhardlimit; + unsigned int dqb_bsoftlimit; + qsize_t dqb_curspace; + time_t dqb_btime; + time_t dqb_itime; +}; + +/* Structure of quotafile info for communication with kernel */ +struct v2_kern_dqinfo { + unsigned int dqi_bgrace; + unsigned int dqi_igrace; + unsigned int dqi_flags; + unsigned int dqi_blocks; + unsigned int dqi_free_blk; + unsigned int dqi_free_entry; +}; + +/* Structure with gathered statistics from kernel */ +struct v2_dqstats { + u_int32_t lookups; + u_int32_t drops; + u_int32_t reads; + u_int32_t writes; + u_int32_t cache_hits; + u_int32_t allocated_dquots; + u_int32_t free_dquots; + u_int32_t syncs; + u_int32_t version; +}; + +#endif diff --git a/quotaio_xfs.h b/quotaio_xfs.h new file mode 100644 index 0000000..e7b7e14 --- /dev/null +++ b/quotaio_xfs.h @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/ + */ +#ifndef _QUOTAIO_XFS_H +#define _QUOTAIO_XFS_H + +#include + +#define XQM_CMD(cmd) ( ('X'<<8)+(cmd) ) +#define IS_XQM_CMD(cmd) ( ((int)(cmd)>>8) == 'X' ) + +/* + * Disk quota - quotactl(2) commands for XFS Quota Manager (XQM). + */ +#define Q_XQUOTAON XQM_CMD(0x1) /* enable quota accounting/enforcement */ +#define Q_XQUOTAOFF XQM_CMD(0x2) /* disable quota accounting/enforcement */ +#define Q_XGETQUOTA XQM_CMD(0x3) /* get disk limits & usage */ +#define Q_XSETQLIM XQM_CMD(0x4) /* set disk limits only */ +#define Q_XGETQSTAT XQM_CMD(0x5) /* returns fs_quota_stat_t struct */ +#define Q_XQUOTARM XQM_CMD(0x6) /* free quota files' space */ + +/* + * fs_disk_quota structure: + * + * This contains the current quota information regarding a user/proj/group. + * It is 64-bit aligned, and all the blk units are in BBs (Basic Blocks) of + * 512 bytes. + */ +#define FS_DQUOT_VERSION 1 /* fs_disk_quota.d_version */ +typedef struct fs_disk_quota { + __s8 d_version; /* version of this structure */ + __s8 d_flags; /* XFS_{USER,PROJ,GROUP}_QUOTA */ + __u16 d_fieldmask; /* field specifier */ + __u32 d_id; /* user, project, or group ID */ + __u64 d_blk_hardlimit; /* absolute limit on disk blks */ + __u64 d_blk_softlimit; /* preferred limit on disk blks */ + __u64 d_ino_hardlimit; /* maximum # allocated inodes */ + __u64 d_ino_softlimit; /* preferred inode limit */ + __u64 d_bcount; /* # disk blocks owned by the user */ + __u64 d_icount; /* # inodes owned by the user */ + __s32 d_itimer; /* zero if within inode limits */ + /* if not, we refuse service */ + __s32 d_btimer; /* similar to above; for disk blocks */ + __u16 d_iwarns; /* # warnings issued wrt num inodes */ + __u16 d_bwarns; /* # warnings issued wrt disk blocks */ + __s32 d_padding2; /* padding2 - for future use */ + __u64 d_rtb_hardlimit; /* absolute limit on realtime blks */ + __u64 d_rtb_softlimit; /* preferred limit on RT disk blks */ + __u64 d_rtbcount; /* # realtime blocks owned */ + __s32 d_rtbtimer; /* similar to above; for RT disk blks */ + __u16 d_rtbwarns; /* # warnings issued wrt RT disk blks */ + __s16 d_padding3; /* padding3 - for future use */ + char d_padding4[8]; /* yet more padding */ +} fs_disk_quota_t; + +/* + * These fields are sent to Q_XSETQLIM to specify fields that need to change. + */ +#define FS_DQ_ISOFT (1<<0) +#define FS_DQ_IHARD (1<<1) +#define FS_DQ_BSOFT (1<<2) +#define FS_DQ_BHARD (1<<3) +#define FS_DQ_RTBSOFT (1<<4) +#define FS_DQ_RTBHARD (1<<5) +#define FS_DQ_LIMIT_MASK (FS_DQ_ISOFT | FS_DQ_IHARD | FS_DQ_BSOFT | \ + FS_DQ_BHARD | FS_DQ_RTBSOFT | FS_DQ_RTBHARD) +/* + * These timers can only be set in super user's dquot. For others, timers are + * automatically started and stopped. Superusers timer values set the limits + * for the rest. In case these values are zero, the DQ_{F,B}TIMELIMIT values + * defined below are used. + * These values also apply only to the d_fieldmask field for Q_XSETQLIM. + */ +#define FS_DQ_BTIMER (1<<6) +#define FS_DQ_ITIMER (1<<7) +#define FS_DQ_RTBTIMER (1<<8) +#define FS_DQ_TIMER_MASK (FS_DQ_BTIMER | FS_DQ_ITIMER | FS_DQ_RTBTIMER) + +/* + * Various flags related to quotactl(2). Only relevant to XFS filesystems. + */ +#define XFS_QUOTA_UDQ_ACCT (1<<0) /* user quota accounting */ +#define XFS_QUOTA_UDQ_ENFD (1<<1) /* user quota limits enforcement */ +#define XFS_QUOTA_GDQ_ACCT (1<<2) /* group quota accounting */ +#define XFS_QUOTA_GDQ_ENFD (1<<3) /* group quota limits enforcement */ + +#define XFS_USER_QUOTA (1<<0) /* user quota type */ +#define XFS_PROJ_QUOTA (1<<1) /* (IRIX) project quota type */ +#define XFS_GROUP_QUOTA (1<<2) /* group quota type */ + +/* + * fs_quota_stat is the struct returned in Q_XGETQSTAT for a given file system. + * Provides a centralized way to get meta infomation about the quota subsystem. + * eg. space taken up for user and group quotas, number of dquots currently + * incore. + */ +#define FS_QSTAT_VERSION 1 /* fs_quota_stat.qs_version */ + +/* + * Some basic infomation about 'quota files'. + */ +typedef struct fs_qfilestat { + __u64 qfs_ino; /* inode number */ + __u64 qfs_nblks; /* number of BBs 512-byte-blks */ + __u32 qfs_nextents; /* number of extents */ +} fs_qfilestat_t; + +typedef struct fs_quota_stat { + __s8 qs_version; /* version number for future changes */ + __u16 qs_flags; /* XFS_QUOTA_{U,P,G}DQ_{ACCT,ENFD} */ + __s8 qs_pad; /* unused */ + fs_qfilestat_t qs_uquota; /* user quota storage information */ + fs_qfilestat_t qs_gquota; /* group quota storage information */ + __u32 qs_incoredqs; /* number of dquots incore */ + __s32 qs_btimelimit; /* limit for blks timer */ + __s32 qs_itimelimit; /* limit for inodes timer */ + __s32 qs_rtbtimelimit; /* limit for rt blks timer */ + __u16 qs_bwarnlimit; /* limit for num warnings */ + __u16 qs_iwarnlimit; /* limit for num warnings */ +} fs_quota_stat_t; + +#endif /* _QUOTAIO_XFS_H */ diff --git a/quotasys.h b/quotasys.h new file mode 100644 index 0000000..10d52b9 --- /dev/null +++ b/quotasys.h @@ -0,0 +1,137 @@ +/* + * + * Headerfile of quota interactions with system - filenames, fstab... + * + */ + +#ifndef _QUOTASYS_H +#define _QUOTASYS_H + +#include +#include +#include "quota.h" + +#define MAXNAMELEN 64 /* Maximal length of user/group name */ +#define MAXTIMELEN 40 /* Maximal length of time string */ +#define MAXNUMLEN 32 /* Maximal length of number */ +#define MAXMNTPOINTS 256 /* Maximal number of mountpoints with quota */ + +/* Flags for formatting time */ +#define TF_ROUND 0x1 /* Should be printed time rounded? */ + +/* Flags for IO initialization */ +#define IOI_LOCALONLY 0x1 /* Operate only on local quota */ +#define IOI_READONLY 0x2 /* Only readonly access */ +#define IOI_OPENFILE 0x4 /* Open file even if kernel has quotas turned on */ + +#define KERN_KNOWN_QUOTA_VERSION (6*10000 + 5*100 + 1) + +/* Interface versions */ +#define IFACE_VFSOLD 1 +#define IFACE_VFSV0 2 +#define IFACE_GENERIC 3 + +/* Kernel quota format and supported interface */ +extern int kernel_formats, kernel_iface; + +/* + * Exported functions + */ +/* Convert quota type to written form */ +char *type2name(int); + +/* Convert username to uid */ +uid_t user2uid(char *); + +/* Convert groupname to gid */ +gid_t group2gid(char *); + +/* Convert user/groupname to id */ +int name2id(char *name, int qtype); + +/* Convert uid to username */ +int uid2user(uid_t, char *); + +/* Convert gid to groupname */ +int gid2group(gid_t, char *); + +/* Convert id to user/group name */ +int id2name(int id, int qtype, char *buf); + +/* Possible default passwd handling */ +#define PASSWD_FILES 0 +#define PASSWD_DB 1 +/* Parse /etc/nsswitch.conf and return type of default passwd handling */ +int passwd_handling(void); + +/* Convert quota format name to number */ +int name2fmt(char *str); + +/* Convert quota format number to name */ +char *fmt2name(int fmt); + +/* Convert kernel to utility format numbers */ +int kern2utilfmt(int fmt); + +/* Convert utility to kernel format numbers */ +int util2kernfmt(int fmt); + +/* Convert time difference between given time and current time to printable form */ +void difftime2str(time_t, char *); + +/* Convert time to printable form */ +void time2str(time_t, char *, int); + +/* Convert number and units to time in seconds */ +int str2timeunits(time_t, char *, time_t *); + +/* Convert number in quota blocks to short printable form */ +void space2str(qsize_t, char *, int); + +/* Convert number to short printable form */ +void number2str(unsigned long long, char *, int); + +/* Check to see if particular quota is to be enabled */ +int hasquota(struct mntent *mnt, int type); + +/* Flags for get_qf_name() */ +#define NF_EXIST 1 /* Check whether file exists */ +#define NF_FORMAT 2 /* Check whether file is in proper format */ +/* Get quotafile name for given entry */ +int get_qf_name(struct mntent *mnt, int type, int fmt, int flags, char **filename); + +/* Detect newest quota format with existing file */ +int detect_quota_files(struct mntent *mnt, int type, int fmt); + +/* Create NULL-terminated list of handles for quotafiles for given mountpoints */ +struct quota_handle **create_handle_list(int count, char **mntpoints, int type, int fmt, + int ioflags, int mntflags); +/* Dispose given list of handles */ +int dispose_handle_list(struct quota_handle **hlist); + +/* Check whether given device name matches quota handle device */ +int devcmp_handle(const char *dev, struct quota_handle *h); + +/* Check whether two quota handles have same device */ +int devcmp_handles(struct quota_handle *a, struct quota_handle *b); + +/* Check kernel supported quotafile format */ +void init_kernel_interface(void); + +/* Check whether is quota turned on on given device for given type */ +int kern_quota_on(const char *dev, int type, int fmt); + +/* Flags for init_mounts_scan() */ +#define MS_NO_MNTPOINT 0x01 /* Specified directory needn't be mountpoint */ +#define MS_NO_AUTOFS 0x02 /* Ignore autofs mountpoints */ +#define MS_QUIET 0x04 /* Be quiet with error reporting */ +/* Initialize mountpoints scan */ +int init_mounts_scan(int dcnt, char **dirs, int flags); + +/* Return next mountpoint for scan */ +struct mntent *get_next_mount(void); + +/* Free all structures associated with mountpoints scan */ +void end_mounts_scan(void); + +#endif /* _QUOTASYS_H */ diff --git a/sysadm.man b/sysadm.man new file mode 100644 index 0000000..274b283 --- /dev/null +++ b/sysadm.man @@ -0,0 +1,101 @@ +Sveucilisni racunski centar SRCE +Hrvatska akademska i istrazivacka mreza + + + Upute za upotrebu CARNet administracijskog programa + +Uvod: + +CARNet administracijski program omogucuje minimalnu administraciju racunala + + - dodavanje korisnika - promjenu ogranicenja disk. prostora (quota) + - brisanje korisnika - operacije nad grupama korisnika + - promjenu lozinki - kreiranje direktorija za rad grupa + - zaustavljanje stroja + +Program se u uobicajenoj konfiguraciji moze koristiti samo sa sistemske +konzole. Na vlastiti rizik mozete u datoteku /etc/sysadmin/config +upisati + +no_console_check + +i tada program vise nece provjeravati je li administrator ulogiran sa +konzole. + +Postupci: + +1. Dodavanje korisnika + +Odabire se opcija 1 -- Dodavanje korisnika +Nakon toga se upisuje login korisnika koji se dodaje, te njegovo +ime i prezime. Program se automatski vraca u glavni meni. + +Nakon sto je korisnik dodan potrebno mu je postaviti lozinku (password), +sto se radi naredbom 3 -- Promjena lozinke korisnika + +2. Brisanje korisnika + +Odabire se opcija 2 -- Brisanje korisnika +Nakon toga se treba upisati login koji se brise. + +3. Promjena lozinke korisnika + +Odabire se opcija 3 -- Promjena lozinke korisnika +Nakon toga se upisuje login kojem se mijenja password, te novi password +koji se utipkava naslijepo 2 puta, zbog provjere. + +4. Promjena quote korisnika + +Odabire se opcija 4 -- Promjena quote korisnika +Nakon toga se unosi login kojem se mijenja ogranicenje diskovnog prostora. +Unose se jos dva broja, jedan koji odredjuje mekani (soft) limit i tvrdi +(hard) limit. Oba broja moraju biti u kilobajtima (KB). Ukoliko se za +vrijednost soft limita unese nula (0), program smatra da korisniku zelite +ukinuti ogranicenje. + +5. Operacije nad grupama korisnika + +Odabire se opcija 5 -- Operacije nad grupama korisnika +Dobije se novi izbornik s 5 opcija: +1 -- Kreiranje nove grupe (mora se napraviti prije nego sto dodajemo +korisnike u grupu). +2 -- Dodavanje korisnika u grupu +3 -- Brisanje korisnika iz grupe +4 -- Brisanje grupe +5 -- Kreiranje direktorija (u koji grupa moze pisati) + Zgodno za timski rad (npr. kreiranje WWW podataka). Direktorij mora biti + na korisnickom disku! +6 -- Brisanje direktorija + Da bi se direktorij mogao obrisati, treba biti prazan! +7 -- Povratak u osnovni izbornik + +6. Zaustavljanje i gasenje racunala + +Odabire se opcija 6 -- Zaustavljanje i gasenje racunala +Ovom naredbom se prekida rad racunala i ono se zaustavlja. +Program pita za poruku koja ce se ispisati korisnicima i +za vrijeme nakon kojeg ce se racunalo ugasiti ("grace period"). +Vrijeme treba biti izmedju 1 i 60 minuta. Ukoliko ovdje unesemo +npr. 0 (ili vise od 60), prekinuti cemo sekvencu. +Nakon sto se racunalo zaustavi, potrebno je ugasiti racunalo +na glavnom prekidacu. Da se racunalo zaustavilo vidi se po +ispisu poruka na ekranu. + +7. Pomoc + +Odabire se opcija 7 -- Pomoc +Upravo je citate :) + +8. Izlazak iz administracijskog programa + +Odabire se opcija 8 -- Izlazak iz administracijskog programa + +------------------------------------------------------------------------------- +Autor programa je Zlatko Calusic + +U slucaju nejasnoca ili problema pisite odrzavatelju na +Zoran Dzelajlija . Zlatko vec jako +dugo nema veze sa ovim programom, iako mu je drago da se +ovaj hack iz 1997. jos uvijek koristi. +------------------------------------------------------------------------------- +Zadnja izmjena: Sun Dec 7 20:12:56 CET 2003 diff --git a/sysadmin.c b/sysadmin.c new file mode 100644 index 0000000..e700d9f --- /dev/null +++ b/sysadmin.c @@ -0,0 +1,1487 @@ +/* + * + * CARNet System Admin Utility v1.26, 2003-12-05 + * + * v1.00, 24 Jun 1996, first release + * v1.10, 17 Oct 1996, directories with ownership of specific group can be created and + * deleted, accounts 'srce' & 'admin' can be added (only) + * v1.15, 30 Oct 1996, admin program is now setuid!!! it gives off privileges + * when not needed + * v1.20, 30 Nov 1996, name changed, logging incorporated, access list, tty checking + * v1.21, 17 Dec 1996, shutdown asks for message and grace period, fixed all + * relative paths (security!), main menu slightly rearranged + * v1.22, 25 Feb 1997, Digital Unix 4.0 only: use user{add,del}(), fix checking for console + * v1.23, 10 Mar 1997, Again problems with OSF/DU and console checking + * v1.24, 12 Mar 1997, Rewritten code for console checking (I *hate* bloody Digital!!!) + * v1.25, 2002-04-28, Initial port to Debian GNU/Linux, limited functionality + * v1.26, 2003-12-05, quota for Linux. Only new style quotactl() on i386. + * + * Written by Zlatko Calusic + * Linux port Zoran Dzelajlija + * + * SRCE, University Computing Centre, Croatia + * CARNet, Croatian Academic and Research Network + * + */ + +/* prototypes */ + +#include "sysadmin.h" + +/* globals */ + +char loginname[MAXLOGIN], group[MAXGROUP], username[MAXNAME], string[MAXSTR]; +char directory[MAXDIR], command[MAXCOMMAND], message[MAXMESS]; +int saveduid, grace; +FILE *logfile; +int conscheck = 1; + +char *authdir, *group_fallback_dir; + + +/* body */ + +void logger(char *fmt, ...) +{ + char *cptr, *whenptr; + va_list arg; + time_t when; + + time(&when); + whenptr = ctime(&when); + if ((cptr = strchr(whenptr, '\n'))) + *cptr = 0; + fprintf(logfile, "%s ", whenptr); + va_start(arg, fmt); + while (*fmt) + { + while (*fmt && *fmt != '%') + fputc(*fmt++, logfile); + fmt++; + switch(*fmt++) + { + case 's': + fprintf(logfile, "%s", va_arg(arg, char *)); + break; + case 'd': + fprintf(logfile, "%d", va_arg(arg, int)); + break; + default: + goto donefmt; + } + } + donefmt: + va_end(arg); + fputc('\n', logfile); + fflush(logfile); + return; +} + +void priv(int pvar) +{ + int retval; + + switch (pvar) + { + case ON: + retval = seteuid(0); + break; + case OFF: + default: + retval = seteuid(saveduid); + } + if (retval < 0) + { + fputs("\nInterna greska, izlazak iz programa!\n", stderr); + waitkey(); + exit(0); + } + return; +} + +int lockpw(void) +{ +#if defined(ultrix) + if (!system("/bin/sh /etc/lockpw")) + return OK; + else + return ERROR; +#elif defined(__osf__) + if (!mkdir("/etc/ptmp", 0700)) + return OK; + else + return ERROR; +#endif + return OK; +} + +void unlockpw(void) +{ +#if defined(ultrix) + system("/bin/sh /etc/unlockpw"); +#elif defined(__osf__) + rmdir("/etc/ptmp"); +#endif + return; +} + +void consexit(void) +{ + fputs("\nProgram se moze pokrenuti samo s konzole.\nIzlazak iz programa!\n", stderr); + exit(1); +} + +int getch(void) +{ + int ch = getchar(); + + if (ch != EOF && ch != '\n') + getchar(); + return ch; +} + +void clear(void) +{ +#if defined(__SVR4) || defined(__osf__) || defined(__linux__) + system("/usr/bin/clear"); +#elif defined(ultrix) + system("/usr/ucb/clear"); +#endif + return; +} + +void waitkey(void) +{ + printf("\nPritisnite za nastavak..."); + while (getch() != '\n'); + return; +} + +void enter(char *var, int size) +{ + char *ptr; + + fgets(var, size, stdin); + if ((ptr = strchr(var, '\n'))) + *ptr = 0; + putchar('\n'); + return; +} + +void getuser(char *text) +{ + printf("%s\n\nUnesite korisnicko ime (login) > ", text); + enter(loginname, MAXLOGIN); + return; +} + +void getgroup(char *text) +{ + if (*text) + printf("%s\n\n", text); + printf("Unesite ime grupe > "); + enter(group, MAXGROUP); + return; +} + +int getname(void) +{ + int count = 0; + + printf("Unesite ime i prezime korisnika > "); + enter(username, MAXNAME); + do + { + if (!isalnum(username[count]) && username[count] != ' ' && username[count] != '.' && username[count] != '-') + { + fputs("Unijeli ste nedozvoljene znakove u imenu korisnika!\n", stderr); + return ERROR; + } + count++; + } while (username[count]); + return OK; +} + +int getdir(void) +{ + int len; + printf("Unesite puni put do direktorija > "); + enter(directory, MAXDIR); + if (strchr(directory, '.') || strstr(directory, "//")) + { + fputs("Unijeli ste nedozvoljene znakove!\n", stderr); + return ERROR; + } + len = strlen(directory); + if (strstr(directory, group_fallback_dir) != directory + || !strcmp(directory, group_fallback_dir)) + { + fprintf(stderr, "Direktorij mora biti podredjen %s direktoriju.\n", + group_fallback_dir); + return ERROR; + } + if (directory[len] == '/') + directory[len] = 0; + return OK; +} + +int getquota(int *soft, int *hard) +{ + printf("Unesite donji limit (soft) u KB > "); + enter(string, MAXSTR); + *soft = atoi(string); + if (*soft < 0 || *soft > MAXQUOTA) + goto error; + if (!*soft) + { + *hard = 0; + return OK; + } + printf("Unesite gornji limit (hard) u KB > "); + enter(string, MAXSTR); + *hard = atoi(string); + if (*hard >= 0 && *hard <= MAXQUOTA) + return OK; + error: + fputs("Unijeli ste nedozvoljenu vrijednost!\n", stderr); + return ERROR; +} + +int testuser(int flag) { +#if defined(__linux__) + char *forbidden[] = { "root", "daemon", "bin", "sys", "sync", "games", "man", + "lp", "mail", "news", "uucp", "proxy", "majordom", + "postgres",/* "www-data",*/ "backup", "msql", "operator", + "list", "irc", "gnats", "nobody", "snort", "ntop", + "mysql", "telnetd", "gdm", "freerad", "" }; +#elif defined(__SVR4) + char *forbidden[] = { "root", "daemon", "bin", "sys", "adm", "lp", + "smtp", "uucp", "nuucp", "listen", "nobody", "noaccess", "ftp", + "gopher", "http", "" }; +#elif defined(__osf__) + char *forbidden[] = { "root", "nobody", "nobodyV", "daemon", "bin", + "uucp", "uucpa", "auth", "cron", "lp", "tcb", "adm", "ris", "ftp", + "gopher", "http", "" }; +#elif defined(ultrix) + char *forbidden[] = { "root", "field", "nobody", "operator", "ris", + "daemon", "sys", "bin", "uucp", "uucpa", "sso", "news", "sccs", + "ingres", "ftp", "gopher", "http", "" }; +#endif + int count = 0; + + if (!*loginname) + return ERROR; + if ((int) strlen(loginname) > 8) { + fputs("Maksimalna duzina korisnickog imena je 8 znakova!\n", stderr); + return ERROR; + } + do { + if (!islower(loginname[count]) && !isdigit(loginname[count])) { + fputs("Unijeli ste nedozvoljene znakove u korisnickom imenu!\n", stderr); + return ERROR; + } + count++; + } while (loginname[count]); + count = 0; + if (flag == ALL && (!strcmp(loginname, "srce") || !strcmp(loginname, "admin"))) + goto fuckoff; + if (authdir) { + struct passwd *pwd; + pwd = getpwnam(loginname); + if (pwd && pwd->pw_dir) + if (strstr(pwd->pw_dir, authdir) != pwd->pw_dir) + goto fuckoff; + } + while (*forbidden[count]) { + if (!strcmp(forbidden[count], loginname)) { + fuckoff: + fputs("Nemate ovlasti za unesenog korisnika!\n", stderr); + return ERROR; + } + count++; + } + return OK; +} + +int testgroup(void) +{ +#if defined(__linux__) + char *forbidden[] = {"root", "daemon", "bin", "sys", "adm", "tty", + "disk", "lp", "mail", "news", "uucp", "proxy", + "kmem", "dialout", "fax", "voice", "cdrom", "tape", + "sudo", "audio", "dip", "majordom", "postgres", + "backup", "msql", "operator", "list", "irc", + "gnats", "shadow", "utmp", "video", "games", + "nogroup", "snort", "mysql", "telnetd", "gdm", + "freerad", "viruser", "" }; +#elif defined(__SVR4) + char *forbidden[] = { "root", "other", "bin", "sys", "adm", "uucp", + "mail", "tty", "lp", "nuucp", "staff", "daemon", "sysadmin", + "nobody", "noaccess", "wheel", "viruser", "" }; +#elif defined(__osf__) + char *forbidden[] = { "system", "daemon", "uucp", "mem", "kmem", "bin", + "sec", "mail", "terminal", "tty", "news", "opr", "auth", "lp", "lpr", + "backup", "cron", "sysadmin", "tape", "tcb", "adm", "operator", + "ris", "nobody", "nogroup", "wheel", "" }; +#elif defined(ultrix) + char *forbidden[] = { "system", "daemon", "uucp", "rsrv3", "bin", "tty", + "kmem", "authread", "news", "rsrv9", "staff", "ris", "guest", + "operator", "admin", "nobody", "wheel", "" }; +#endif + int count = 0; + + if (!*group) + return ERROR; + if ((int) strlen(group) > 8) { + fputs("Maksimalna duzina imena grupe je 8 znakova!\n", stderr); + return ERROR; + } do { + if (!islower(group[count])) { + fputs("Unijeli ste nedozvoljene znakove u imenu grupe!\n", stderr); + return ERROR; + } + count++; + } while (group[count]); + count = 0; + while (*forbidden[count]) { + if (!strcmp(forbidden[count], group)) { + fputs("Nemate ovlasti za unesenu grupu!\n", stderr); + return ERROR; + } + count++; + } + if (authdir) { + struct group *grp = getgrnam(group); + if (grp && grp->gr_mem) { + struct passwd *pwd; + for (; *grp->gr_mem; grp->gr_mem++) { + pwd = getpwnam(*grp->gr_mem); + if (pwd && pwd->pw_dir) { + if (strstr(pwd->pw_dir, authdir) != pwd->pw_dir) { + fputs("Nemate ovlasti za unesenu grupu!\n", stderr); + return ERROR; + } else + break; + } + } + } + } + return OK; +} + +int system_default_shell_check(void) +{ + #ifndef __linux__ + return 0; + #endif + + struct stat statp; + statp.st_mode = 0; + + (void) stat("/etc/default/useradd", &statp); + /* regular file? */ + if (! statp.st_mode) return 0; + if (S_ISREG(statp.st_mode)) { + /* XXX maybe check file contents */ + return 1; + } else { + return 0; + } +} + +void adduser(void) +{ + char fullhm[200]; + char *shellopt=""; + int l; + getuser("Dodavanje korisnika:"); + if (testuser(NOTALL) == OK && getname() == OK) { + strncpy(fullhm, authdir ? authdir : HM, 199); + l = strlen(fullhm); + if (fullhm[l - 1] != '/') { + fullhm[l] = '/'; + fullhm[l + 1] = '\0'; + } + strncat(fullhm, loginname, 199); + logger("USER ADD: user %s, fullname %s", loginname, username); +#if defined(__SVR4) || defined (__linux__) + if (!system_default_shell_check()) { + shellopt = "-s " DEFAULTSHELL; + } + sprintf(command, "/usr/sbin/useradd -m -d %s %s" \ + " -c \"%s\" %s", fullhm, shellopt, username, loginname); + printf("%s\n", command); + priv(ON); + if (!system(command)) { + priv(OFF); + #if defined (__linux__) + /* Avoid race */ + sync(); + #endif /* __linux__ */ + sprintf(command, "/usr/bin/passwd %s", loginname); + priv(ON); + system(command); + } +#elif defined(__osf__) +#if defined(DU4) + sprintf(command, "/usr/sbin/useradd -m -s " DEFAULTSHELL \ + " -c \"%s\" %s", username, loginname); + priv(ON); + if (!system(command)) { + struct pr_passwd *pr; + + if (!(pr = getprpwnam(loginname))) { + perror("getprpwnam"); + goto problems; + } + pr->uflg.fg_lock = 1; + pr->uflg.fg_min = 1; + pr->ufld.fd_min = 0; + pr->uflg.fg_expire = 1; + pr->ufld.fd_expire = 0; + pr->uflg.fg_lifetime = 1; + pr->ufld.fd_lifetime = 0; + pr->uflg.fg_max_tries = 1; + pr->ufld.fd_max_tries = 0; + if (!putprpwnam(loginname, pr)) { + perror("putprpwnam"); + goto problems; + } + sprintf(command, "/usr/bin/passwd %s", loginname); + system(command); + } +#else + sprintf(command, "/usr/sbin/sysadm.adduser %s \"%s\"", loginname, username); + priv(ON); + system(command); +#endif /* DU4 */ +#elif defined(ultrix) + sprintf(command, "/usr/etc/sysadm.adduser %s \"%s\"", loginname, username); + priv(ON); + system(command); +#endif +#if defined(DU4) + problems: +#endif + priv(OFF); + } + waitkey(); + return; +} + +void rmuser(void) +{ + getuser("Brisanje korisnika:"); + if (testuser(ALL) == OK) { + logger("USER REMOVE: user %s", loginname); +#if defined(__SVR4) || defined(__linux__) + sprintf(command, "/usr/sbin/userdel -r %s", loginname); +#elif defined(__osf__) + #if defined(DU4) + sprintf(command, "/usr/sbin/userdel -r %s", loginname); + #else + sprintf(command, "/usr/sbin/sysadm.removeuser %s", loginname); + #endif +#elif defined(ultrix) + sprintf(command, "/usr/etc/sysadm.removeuser %s", loginname); +#endif + priv(ON); + system(command); + priv(OFF); + } + waitkey(); + return; +} + +void chpass(void) +{ + getuser("Promjena korisnicke lozinke:"); + if (testuser(NOTALL) == OK) { + logger("PASSWD CHANGE: user %s", loginname); + sprintf(command, "/usr/bin/passwd %s", loginname); + priv(ON); + system(command); + priv(OFF); + } + waitkey(); + return; +} + +void chquota(void) +{ + int soft, hard; + struct passwd *pwd; +#if defined(__SVR4) + struct dqblk qval; + struct quotctl qstr; + struct stat statbuf; +#elif defined(ultrix) + struct dqblk qval; + struct stat statbuf; +#elif defined(__linux__) + #if defined(__i386__) + struct if_dqblk qval; /* sys/quota.h is wrong for 2.4.23/i386 */ + #elif defined(__sparc__) + struct dqblk qval; /* 2.4.23/sparc is different */ + #endif + struct stat statbuf; + struct mntent *mntp; + FILE *fp; + int dev; + char devname[MAXDIR], mountpoint[MAXDIR], greska[MAXDIR]; + time_t now; + devname[0] = '\0'; +#endif + + getuser("Promjena korisnicke quote:"); + if (testuser(ALL) != OK) { + priv(OFF); + waitkey(); + return; + } + + if (!(pwd = getpwnam(loginname))) { + fputs("Ne postoji uneseni korisnik!\n", stderr); + waitkey(); + return; + } + +#if defined(__linux__) + priv(ON); + if (stat(pwd->pw_dir, &statbuf) < 0) { + priv(OFF); + fputs("Korisnik nema maticni direktorij!\n", stderr); + waitkey(); + return; + } else { + priv(OFF); + dev = statbuf.st_dev; + } + + priv(ON); + if (!(fp = setmntent("/etc/mtab", "r"))) { + priv(OFF); + perror("setmntent"); + waitkey(); + return; + } + while (feof(fp) == 0) { + mntp = getmntent(fp); + if (!mntp) break; + /* ignore special fs' like proc, devfs... */ + if (strncmp(mntp->mnt_fsname, "/dev", 4)) + continue; + if (stat(mntp->mnt_fsname, &statbuf) < 0) { + priv(OFF); + perror("stat"); + endmntent(fp); + waitkey(); + return; + } + if (statbuf.st_rdev == dev) { + strncpy(devname, mntp->mnt_fsname, MAXDIR); + strncpy(mountpoint, mntp->mnt_dir, MAXDIR); + break; + } + } + endmntent(fp); + priv(OFF); + + if(! strlen(devname)) + { + fputs("Nije pronadjen device na kojem je korisnikov direktorij!\n", stderr); + waitkey(); + return; + } + + #ifdef __i386__ + /* get previous quota values and update times */ + priv(ON); + if (!quotactl(QCMD(Q_GETQUOTA, USRQUOTA), devname, pwd->pw_uid, (caddr_t) &qval)) { + priv(OFF); + time(&now); + if (qval.dqb_bsoftlimit && ( + #if defined (__i386__) + qval.dqb_curspace + #elif defined (__sparc__) + qval.dqb_curblocks + #endif + /1024) >= qval.dqb_bsoftlimit) { + if (!qval.dqb_btime) + qval.dqb_btime = now + MAX_DQ_TIME; + } + else + qval.dqb_btime = 0; + if (qval.dqb_isoftlimit && qval.dqb_curinodes >= qval.dqb_isoftlimit) { + if (!qval.dqb_itime) + qval.dqb_itime = now + MAX_DQ_TIME; + } + else + qval.dqb_itime = 0; + } else { + priv(OFF); + fputs("Ne mogu utvrditi trenutne vrijednosti quote!\n", stderr); + waitkey(); + return; + } + #endif +#endif + + if (getquota(&soft, &hard) == OK) { + logger("QUOTA CHANGE: user %s, soft %d, hard %d", loginname, soft, hard); +#ifdef __SVR4 + int i, count, fd; +#endif + if (!soft) + fputs("Korisnik ce imati neogranicen pristup diskovnom prostoru!\n", stderr); +#if defined(__linux__) + #if defined(__i386__) + /* Actually most of these are u_int64_t. */ + qval.dqb_bsoftlimit = (u_int32_t) soft; + qval.dqb_bhardlimit = (u_int32_t) hard; + qval.dqb_isoftlimit = qval.dqb_ihardlimit = (u_int32_t) 0; + qval.dqb_btime = (time_t) now + MAX_DQ_TIME; + qval.dqb_itime = (time_t) now + MAX_IQ_TIME; + #if defined(__i386__) + /* Set limits and times */ + qval.dqb_valid = QIF_LIMITS | QIF_TIMES; + #endif + priv(ON); + if (! + #if defined (__i386__) + quotactl(QCMD(Q_SETQUOTA, USRQUOTA), devname, pwd->pw_uid, (caddr_t) &qval) + #elif defined (__sparc__) + quotactl(QCMD(Q_SETQLIM, USRQUOTA), devname, pwd->pw_uid, (caddr_t) &qval) + #endif + ) + #elif defined (__sparc__) + sprintf(command, "/usr/sbin/setquota %s -T %d %d %s", \ + loginname, MAX_DQ_TIME, MAX_IQ_TIME, mountpoint); + printf("%s\n", command); + priv(ON); + if (!system(command)) { + priv(OFF); + /* fputs("Vremensko ogranicenje quote postavljeno.\n", stderr); */ + } + else { + priv(OFF); + fputs("Nije uspjelo postavljanje vremenskog ogranicenja quote!\n", stderr); + waitkey(); + return; + } + sprintf(command, "/usr/sbin/setquota %s %d %d %d %d %s", \ + loginname, soft, hard, 0, 0, mountpoint); + printf("%s\n", command); + priv(ON); + if (!system(command)) + #endif /* __sparc__ */ + { + priv(OFF); + fputs("Quota uspjesno promijenjena.\n", stderr); + } + else { + priv(OFF); + if (errno == 3) { + sprintf(greska, "Quota nije ukljucena na filesystemu %s!\n", devname); + fputs(greska, stderr); + } else { + perror("quotactl"); + } + } +#elif defined(__SVR4) + qstr.uid = pwd->pw_uid; + for (count = 1; ; count++) + { + char *ptr; + + strcpy(string, pwd->pw_dir); + for (i = 0; i < count; i++) + { + ptr = strrchr(string, '/'); + if (ptr) + *ptr = 0; + else + goto noquota; + } + strcat(string, "/quotas"); + priv(ON); + if (!stat(string, &statbuf) && (fd = open(string, O_RDWR)) > 0) + goto success; + priv(OFF); + } + noquota: + fputs("Nema quote na ovom sistemu!\n", stderr); + waitkey(); + return; + success: + priv(OFF); + qval.dqb_bsoftlimit = (u_long) soft << 1; + qval.dqb_bhardlimit = (u_long) hard << 1; + qval.dqb_fsoftlimit = qval.dqb_fhardlimit = (u_long) 0; + qval.dqb_btimelimit = (u_long) DQ_BTIMELIMIT; + qval.dqb_ftimelimit = (u_long) DQ_FTIMELIMIT; + qstr.addr = (caddr_t) &qval; + qstr.op = Q_SETQLIM; + priv(ON); + if (!ioctl(fd, Q_QUOTACTL, &qstr)) + fputs("Quota uspjesno promijenjena.\n", stderr); + else + perror("quotactl"); +#elif defined(__osf__) + qval.dqb_bsoftlimit = (u_long) soft << 1; + qval.dqb_bhardlimit = (u_long) hard << 1; + qval.dqb_isoftlimit = qval.dqb_ihardlimit = (u_int) 0; + qval.dqb_btime = (time_t) MAX_DQ_TIME; + qval.dqb_itime = (time_t) MAX_IQ_TIME; + priv(ON); + if (!quotactl(pwd->pw_dir, QCMD(Q_SETQUOTA, USRQUOTA), pwd->pw_uid, (char *) &qval)) + fputs("Quota uspjesno promijenjena.\n", stderr); + else + perror("quotactl"); +#elif defined(ultrix) + priv(ON); + if (stat(pwd->pw_dir, &statbuf) < 0) + { + priv(OFF); + fputs("Korisnik nema maticni direktorij!\n", stderr); + waitkey(); + return; + } + priv(OFF); + qval.dqb_bsoftlimit = (u_long) soft << 1; + qval.dqb_bhardlimit = (u_long) hard << 1; + qval.dqb_isoftlimit = qval.dqb_ihardlimit = (u_short) 0; + qval.dqb_bwarn = (u_char) MAX_DQ_WARN; + qval.dqb_iwarn = (u_char) MAX_IQ_WARN; + qval.dqb_curblocks = (u_long) 0; + qval.dqb_curinodes = (u_short) 0; + priv(ON); + if (!quota(Q_SETDLIM, pwd->pw_uid, statbuf.st_dev, (caddr_t) &qval)) + fputs("Quota uspjesno promijenjena.\n", stderr); + else + perror("quota"); +#endif + } + priv(OFF); + waitkey(); + return; +} + +void opgroup(void) +{ + char ch; + int oldumask; + + for (;;) + { + priv(OFF); + banner(); + puts("Operacije nad grupama korisnika:\n"); + puts("1 -- Kreiranje nove grupe"); + puts("2 -- Dodavanje korisnika u grupu"); + puts("3 -- Brisanje korisnika iz grupe"); + puts("4 -- Brisanje grupe"); + puts("5 -- Kreiranje direktorija (u koji grupa moze pisati)"); + puts("6 -- Brisanje direktorija\n"); + puts("7 -- Povratak u osnovni izbornik\n"); + printf("Unesite odabir > "); + ch = getch(); + clear(); + switch(ch) + { + case '1': + getgroup("Kreiranje nove grupe:"); + if (testgroup() == OK) + { + logger("GROUP CREATE: group %s", group); +#if defined(__SVR4) || defined(__linux__) + sprintf(command, "/usr/sbin/groupadd %s", group); +#elif defined(__osf__) + sprintf(command, "/usr/sbin/sysadm.addgroup %s", group); +#elif defined(ultrix) + sprintf(command, "/usr/etc/sysadm.addgroup %s", group); +#endif + priv(ON); + system(command); + priv(OFF); + } + waitkey(); + break; + case '2': + getuser("Dodavanje korisnika u grupu:"); + if (testuser(ALL) == OK) + { + if (getpwnam(loginname)) + { + getgroup(""); + if (testgroup() == OK) + { + FILE *readfp, *writefp; + char line[2048]; + int found = 0; + + logger("ADD USER TO GROUP: user %s, group %s", loginname, group); + priv(ON); + if (lockpw() == ERROR) + { + priv(OFF); +#ifdef __osf__ + fputs("Probajte malo kasnije, /etc/group je u upotrebi!\n", stderr); +#endif + goto getout; + } + if (!(readfp = fopen("/etc/group", "rt"))) + { + priv(OFF); + fputs("Ne mogu otvoriti /etc/group datoteku!\n", stderr); + goto getout; + } + unlink("/tmp/group"); + if (!(writefp = fopen("/tmp/group", "wt"))) + { + fclose(readfp); + priv(OFF); + fputs("Ne mogu otvoriti privremenu datoteku!\n", stderr); + goto getout; + } + while (fgets(line, 2048, readfp)) + { + if (strstr(line, group) == line && line[strlen(group)] == ':') + { + char *ptr, left, right; + + if ((ptr = strstr(line, loginname))) + { + + left = *(ptr - 1); + right = *(ptr + strlen(loginname)); + if ((left == ':' || left == ',') && + (right == ',' || right == '\n')) + { + fclose(readfp); + fclose(writefp); + unlink("/tmp/group"); + priv(OFF); + fputs("Korisnik je vec u unesenoj grupi!\n", stderr); + goto getout; + } + } + if ((ptr = strrchr(line, '\n'))) + *ptr = 0; + else + { + fclose(readfp); + fclose(writefp); + unlink("/tmp/group"); + priv(OFF); + fputs("Problem s datotekom /etc/group!\n", stderr); + goto getout; + } + if (*(ptr - 1) != ':') + strcat(line, ","); + strcat(line, loginname); + strcat(line, "\n"); + found = 1; + } + fputs(line, writefp); + if (ferror(writefp)) + { + fclose(readfp); + fclose(writefp); + unlink("/tmp/group"); + priv(OFF); + fputs("Problem prilikom pisanja privremene datoteke!\n", stderr); + goto getout; + } + } + fclose(readfp); + fclose(writefp); + if (found) + { + system("/bin/mv /tmp/group /etc/group"); + priv(OFF); + fputs("Korisnik uspjesno dodan u grupu.\n", stderr); + } + else + { + unlink("/tmp/group"); + priv(OFF); + fputs("Ne postoji unesena grupa!\n", stderr); + } + } + } + else + fputs("Ne postoji uneseni korisnik!\n", stderr); + } + getout: + priv(ON); + unlockpw(); + priv(OFF); + waitkey(); + break; + case '3': + getuser("Brisanje korisnika iz grupe:"); + if (testuser(ALL) == OK) + { + if (getpwnam(loginname)) + { + getgroup(""); + if (testgroup() == OK) + { + FILE *readfp, *writefp; + char line[2048]; + int found = 0, empty = 0; + + logger("REMOVE USER FROM GROUP: user %s, group %s", loginname, group); + priv(ON); + if (lockpw() == ERROR) + { + priv(OFF); +#ifdef __osf__ + fputs("Probajte malo kasnije, /etc/group je u upotrebi!\n", stderr); +#endif + goto getout1; + } + if (!(readfp = fopen("/etc/group", "rt"))) + { + priv(OFF); + fputs("Ne mogu otvoriti /etc/group datoteku!\n", stderr); + goto getout1; + } + unlink("/tmp/group"); + if (!(writefp = fopen("/tmp/group", "wt"))) + { + fclose(readfp); + priv(OFF); + fputs("Ne mogu otvoriti privremenu datoteku!\n", stderr); + goto getout1; + } + while (fgets(line, 2048, readfp)) + { + if (strstr(line, group) == line && line[strlen(group)] == ':') + { + char *ptr, left, right; + + if ((ptr = strstr(line, loginname))) + { + left = *(ptr - 1); + right = *(ptr + strlen(loginname)); + if ((left == ':' || left == ',') && + (right == ',' || right == '\n')) + goto ok; + + } + fclose(readfp); + fclose(writefp); + unlink("/tmp/group"); + priv(OFF); + fputs("Korisnik nije u unesenoj grupi!\n", stderr); + goto getout1; + ok: + if (right != '\n') + strcpy(ptr, ptr + strlen(loginname) + 1); + else if (left != ':') + strcpy(ptr - 1, "\n"); + else + { + empty = 1; + strcpy(ptr, "\n"); + } + found = 1; + } + fputs(line, writefp); + if (ferror(writefp)) + { + fclose(readfp); + fclose(writefp); + unlink("/tmp/group"); + priv(OFF); + fputs("Problem prilikom pisanja privremene datoteke!\n", stderr); + goto getout1; + } + } + fclose(readfp); + fclose(writefp); + if (found) + { + system("/bin/mv /tmp/group /etc/group"); /* JUNK */ + priv(OFF); + fputs("Korisnik uspjesno obrisan iz grupe.\n", stderr); + if (empty) + fputs("U grupi nema vise ni jednog korisnika.\n", stderr); + } + else + { + unlink("/tmp/group"); + priv(OFF); + fputs("Ne postoji unesena grupa!\n", stderr); + } + } + } + else + fputs("Ne postoji uneseni korisnik!\n", stderr); + } + getout1: + priv(ON); + unlockpw(); + priv(OFF); + waitkey(); + break; + case '4': + getgroup("Brisanje grupe:"); + if (testgroup() == OK) + { + logger("GROUP REMOVE: group %s", group); +#if defined(__SVR4) || defined(__linux__) + sprintf(command, "/usr/sbin/groupdel %s", group); +#elif defined(__osf__) + sprintf(command, "/usr/sbin/sysadm.removegroup %s", group); +#elif defined(ultrix) + sprintf(command, "/usr/etc/sysadm.removegroup %s", group); +#endif + priv(ON); + system(command); + priv(OFF); + } + waitkey(); + break; + case '5': + oldumask = umask(002); + if (getdir() == OK) + { + getgroup("Grupa u cije vlasnistvo zelite staviti direktorij:"); + if (testgroup() == OK) + { + struct group *grpptr; + int i, status; + + grpptr = getgrnam(group); + if (!grpptr) + { + fputs("Trazena grupa ne postoji!\n", stderr); + goto donedir; + } + logger("DIRECTORY CREATE: directory %s, group %s", directory, group); + for (i = 1;;i++) + { + while (directory[i] && directory[i] != '/') + i++; + if (directory[i]) + { + directory[i] = 0; + priv(ON); + status = mkdir(directory, 0755); + if (status < 0 && errno != EEXIST) + { + priv(OFF); + perror("mkdir"); + goto donedir; + } + priv(OFF); + directory[i] = '/'; + } + else + { + priv(ON); + status = mkdir(directory, 0775); + if (status < 0 && errno != EEXIST) + { + perror("mkdir"); + goto donedir; + } + errno = 0; + if (chown(directory, (uid_t) -1, grpptr->gr_gid) < 0) + perror("chown"); + else + fputs("Direktorij uspjesno kreiran.\n", stderr); + goto donedir; + } + } + } + } + donedir: + priv(OFF); + umask(oldumask); + waitkey(); + break; + case '6': + if (getdir() == OK) + { + logger("DIRECTORY REMOVE: directory %s", directory); + priv(ON); + if (rmdir(directory) < 0) + perror("rmdir"); + else + fputs("Direktorij uspjesno obrisan.\n", stderr); + priv(OFF); + } + waitkey(); + break; + case '7': + case 'Q': + case 'q': + return; + default: + break; + } + } +} + +void shutdown(void) +{ + int count = 0; + + printf("Unesite poruku za korisnike > "); + enter(message, MAXMESS); + do + { + if (!isalpha(message[count]) && !isspace(message[count]) && !isdigit(message[count]) && message[count] != '.' && message[count] != ',' && message[count] != '_' && message[count] != '-' && message[count] != '=') + { + priv(OFF); + fputs("Unijeli ste nedozvoljene znakove u poruci!\n", stderr); + waitkey(); + return; + } + count++; + } while (message[count]); + printf("\nUnesite vrijeme kroz koje ce se racunalo zaustaviti (1 - 60 min) > "); + enter(string, MAXSTR); + grace = atoi(string); + if (grace < MINGRACE || grace > MAXGRACE) + { + priv(OFF); + fprintf(stderr, "Unijeli ste vrijeme koje je nula, negativno ili preveliko!\n"); + waitkey(); + return; + } +#if defined(__SVR4) + grace *= 60; +#endif + puts("Pokrenuta je procedura za zaustavljanje racunala!\n"); + logger("SHUTDOWN!"); +#if defined(__SVR4) + sprintf(command, "/usr/sbin/shutdown -i0 -y -g%d \"%s\"", grace, message); +#elif defined(__osf__) || defined (__linux__) + sprintf(command, "/sbin/shutdown -h +%d %s", grace, message); +#elif defined(ultrix) + sprintf(command, "/bin/shutdown -h +%d %s", grace, message); +#endif + priv(ON); + system(command); + priv(OFF); + loop: + sleep(10); + goto loop; + waitkey(); + return; +} + +void manual(void) +{ + FILE* manual; + char line[256]; + int count = 0; + + logger("MANUAL READ"); + priv(ON); + if (!(manual = fopen(MANFILE, "rt"))) + { + priv(OFF); + fputs("Uputstva nisu instalirana!\n", stderr); + waitkey(); + return; + } + priv(OFF); + while (fgets(line, 256, manual)) + { + fputs(line, stdout); + if (count++ == 21) + { + waitkey(); + clear(); + count = 0; + } + } + fclose(manual); + waitkey(); + return; +} + +void banner(void) +{ + clear(); + puts(VERSION); + return; +} + +void console_check(char *name) +{ + char *cptr; + int oncon = 0; + struct stat statbuf; + struct utmp entry; + FILE *fp; + + priv(OFF); + if (isatty(0)) + cptr = ttyname(0); + else + { + fprintf(stderr, "\nProblem s terminalom.\nIzlazak iz programa!\n"); + exit(1); + } + if (!cptr || strcmp(cptr, CONSOLE)) + { + if (stat(CONSOLE, &statbuf) < 0) + { + fprintf(stderr, "\nNe mogu provjeriti vlasnistvo /dev/console.\nIzlazak iz programa!\n"); + exit(1); + } + if (statbuf.st_uid == saveduid) + return; +#if defined(__SVR4) + else + consexit(); +#endif + +#if defined(__osf__) || defined(ultrix) || defined(__linux__) + if (strstr(cptr, "/dev/") == cptr) + strcpy(cptr, cptr + 5); + fp = fopen(UTMP_FILE, "r"); + if (!fp) + { + priv(OFF); + fprintf(stderr, "\nNe mogu otvoriti utmp datoteku.\nIzlazak iz programa!\n"); + exit(1); + } + while (fread(&entry, sizeof(entry), 1, fp)) + { + #if defined(__linux__) + entry.ut_line[UT_LINESIZE-1] = 0; + entry.ut_user[UT_NAMESIZE-1] = 0; + entry.ut_host[UT_HOSTSIZE-1] = 0; + #else + entry.ut_line[8] = 0; + entry.ut_name[8] = 0; + entry.ut_host[16] = 0; + #endif + #if defined (__linux__) + if (entry.ut_type == DEAD_PROCESS) + continue; + if (strncmp(entry.ut_line, cptr, UT_LINESIZE-1)) + continue; + if (!strncmp(entry.ut_line, "tty", 3) && \ + entry.ut_line[3] >= '0' && \ + entry.ut_line[3] <= '9' && \ + !strncmp(entry.ut_user, name, UT_NAMESIZE-1)) { + oncon = 1; + break; + } + else if (!strncmp(entry.ut_host, ":0", 2) && \ + !strncmp(entry.ut_user, name, UT_NAMESIZE-1)) { + oncon = 1; + break; + } + else + break; /* pravi tty, a nije na konzoli */ + #else + if (strncmp(entry.ut_line, cptr, 8)) + continue; + if (!strncmp(entry.ut_line, ":0", 2) && !strncmp(entry.ut_name, name, 8)) + { + oncon = 1; + break; + } + if (!strncmp(entry.ut_host, ":0.0", 8) || !strncmp(entry.ut_host, "local", 8)) { + oncon = 1; + break; + } + #endif /* __linux__ */ + } + fclose(fp); + if (!oncon) + consexit(); +#endif + } + return; +} + + +int main(int argc, char **argv) +{ + char ch, *cptr; + int allowed; + FILE *aclfile; + FILE *conffile; + struct passwd *acl = NULL; + char adminlogin[64], adminfull[1024]; + char *p; + +#if defined(DU4) + set_auth_parameters(argc,argv); +#endif + umask(022); + putenv("IFS=\" \""); + signal(SIGINT, SIG_IGN); + signal(SIGTSTP, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + signal(SIGPIPE, SIG_IGN); + saveduid = getuid(); + setuid(0); + chmod(LOGFILE, 0600); + chmod(ACLFILE, 0600); + chown(LOGFILE, 0, -1); + chown(ACLFILE, 0, -1); + if (!(logfile = fopen(LOGFILE, "a"))) + { + priv(OFF); + perror("fopen"); + fprintf(stderr, "\nNe mogu otvoriti log datoteku.\nIzlazak iz programa!\n"); + exit(1); + } + if (saveduid) + { + if (!(aclfile = fopen(ACLFILE, "r"))) + { + priv(OFF); + perror("fopen"); + fprintf(stderr, "\nNe mogu otvoriti datoteku kontrole pristupa.\nIzlazak iz programa!\n"); + exit(1); + } + allowed = 0; + while (fgets(string, MAXSTR, aclfile)) + { + if (*string == '#') + continue; + authdir = group_fallback_dir = NULL; + for (p = string; *p && !isspace(*p); p++); + cptr = p; + if (*p && *p != '\n') + { + while (isspace(*p)) + ++p; + authdir = p; + while (*p && !isspace(*p)) + ++p; + if (*p != '\n') + { + *p++ = '\0'; + group_fallback_dir = p; + while (*p && !isspace(*p)) + ++p; + *p = '\0'; + group_fallback_dir = strdup(group_fallback_dir); + } + else + *p = '\0'; + } + *cptr = 0; + if ((acl = getpwnam(string)) && acl->pw_uid == saveduid) + { + if (authdir) + authdir = strdup(authdir); + else + authdir = NULL; + allowed = 1; + break; + } + } + fclose(aclfile); + if (!group_fallback_dir) + group_fallback_dir = authdir ? authdir : HM; + if (!allowed) + { + priv(OFF); + fprintf(stderr, "\nNemate dozvolu za koristenje programa.\nIzlazak iz programa!\n"); + exit(1); + } + priv(ON); + if (!(conffile = fopen(OPTFILE, "r"))) { + priv(OFF); +/* perror("fopen"); + fprintf(stderr, "Ne mogu otvoriti datoteku s konfiguracijskim opcijama.\n"); + sleep(2); +*/ } + else { + priv(OFF); + while (fgets(string, MAXSTR, conffile)) { + p = &string[strlen(string)-1]; + if (*p == '\n') + *p = '\0'; + if (!strncmp(string, CONF_NOCONSOLE, MAXSTR-1)) + conscheck = 0; + } + fclose(conffile); + } + + if (!authdir && conscheck) + console_check(acl->pw_name); + } + else + { + authdir = NULL; + group_fallback_dir = HM; + acl = getpwuid(0); + } + if (acl && acl->pw_name) + strcpy(adminlogin, acl->pw_name); + else + strcpy(adminlogin, "(none)"); + if (acl && acl->pw_gecos) + strcpy(adminfull, acl->pw_gecos); + else + strcpy(adminfull, "NULL"); + logger("ADMIN START: admin %s (%s)", adminlogin, adminfull); + for (;;) + { + priv(OFF); + banner(); + puts("1 -- Dodavanje korisnika"); + puts("2 -- Brisanje korisnika"); + puts("3 -- Promjena lozinke korisnika"); + puts("4 -- Promjena quote korisnika\n"); + puts("5 -- Operacije nad grupama korisnika\n"); + puts("6 -- Zaustavljanje i gasenje racunala\n"); + puts("7 -- Pomoc\n"); + puts("8 -- Izlazak iz administracijskog programa\n"); + printf("Unesite odabir > "); + ch = getch(); + clear(); + switch(ch) + { + case '1': + adduser(); + break; + case '2': + rmuser(); + break; + case '3': + chpass(); + break; + case '4': + chquota(); + break; + case '5': + opgroup(); + break; + case '6': + shutdown(); + break; + case '7': + case 'h': + case '?': + manual(); + break; + case '0': + case '8': + case 'Q': + case 'q': + clear(); + logger("ADMIN END: admin %s (%s)", adminlogin, adminfull); + fclose(logfile); + exit(0); + default: + break; + } + } +} diff --git a/sysadmin.h b/sysadmin.h new file mode 100644 index 0000000..b79de61 --- /dev/null +++ b/sysadmin.h @@ -0,0 +1,138 @@ +#ifdef ultrix +# define POSIX +# define __POSIX +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "version.h" + +/* HM's must have / at the end !!! */ + +#if defined(__linux__) + #define HM "/home/" + #if defined(__i386__) + #include "quota.h" /* From quota-3.09, works only for new quota! */ + #include "quotaio.h" + #include "dqblk_v2.h" + #include + #elif defined(__sparc__) + #include + #include + #else + #error Unknown architecture! + #endif +#elif defined(__SVR4) + #define HM "/home/" + #include +#elif defined(__osf__) + #if defined(DU4) + #define HM "/home/" + #include + #include + #include + int quotactl(char *, int, int, char *); + #else + #define HM "/usr/users/" + #include + int quotactl(char *, int, int, char *); + #endif +#elif defined(ultrix) + #define HM "/usr/users/" + #include + #include + int quota(int, int, int, caddr_t); + extern int setreuid(uid_t, uid_t); + extern int seteuid(uid_t); + extern int putenv(char *); +#endif + +#define ALL 0 /* forbidden + srce + admin */ +#define NOTALL 1 /* only forbidden */ +#define ERROR 2 /* error condition */ +#define OK 3 /* everything's fine */ + +#define OFF 0 /* drop privileges */ +#define ON 1 /* get priviliges */ + +#define MAXLOGIN 16 /* max login size + 1 */ +#define MAXGROUP 16 /* max group name + 1 */ +#define MAXNAME 64 /* max username size + 1 */ +#define MAXSTR 64 /* max input string for quota numbers + 1 */ +#define MAXDIR 1024 /* max pathlen */ +#define MAXCOMMAND 256 /* max string length for system() */ +#define MAXQUOTA 262144 /* max quota in KB */ +#define MAXMESS 200 /* max message length for shutdown */ +#define MINGRACE 1 /* min grace period for shutdown */ +#define MAXGRACE 60 /* max grace period for shutdown */ + +#define CONSOLE "/dev/console" /* console device */ + +#define CONF_NOCONSOLE "no_console_check" /* Config: don't check for console */ + +#if defined (__linux__) || defined(__SVR4) + #define LOGFILE "/var/log/sysadmin.log" /* logfile */ + #define ACLFILE "/etc/sysadmin/users" /* acl file */ + #define OPTFILE "/etc/sysadmin/config" /* config */ + #if defined (__linux__) + #define MANFILE "/usr/share/sysadmin/sysadm.man" /* online manual */ + #define PARSE_USERADD_DEFAULTS 1 + #else /* __SVR4 */ + #define MANFILE "/usr/local/share/sysadmin/sysadm.man" /* online manual */ + #endif +#else + #define LOGFILE "/var/adm/adminlog" /* logfile */ + #define ACLFILE "/etc/adminusers" /* acl file */ + #define OPTFILE "/etc/adminconfig" /* config */ + #define MANFILE "/etc/sysadm.man" /* online manual */ +#endif + +#if defined(__linux__) + #define DEFAULTSHELL "/bin/bash" +#else + #define DEFAULTSHELL "/bin/csh" +#endif + +/* function prototypes */ + +void logger(char *, ...); +void printpriv(char *); +void priv(int); +int lockpw(void); +void unlockpw(void); +void consexit(void); +int getch(void); +void clear(void); +void waitkey(void); +void enter(char *, int); +void getuser(char *); +void getgroup(char *); +int getname(void); +int getdir(void); +int getquota(int *, int *); +int testuser(int); +int testgroup(void); +int system_default_shell_check(void); +void adduser(void); +void rmuser(void); +void chpass(void); +void chquota(void); +void opgroup(void); +void shutdown(void); +void manual(void); +void banner(void); +void console_check(char *); diff --git a/sysadmin.html b/sysadmin.html new file mode 100644 index 0000000..902b986 --- /dev/null +++ b/sysadmin.html @@ -0,0 +1,170 @@ + + + +sysadmin v1.20 + + + +

sysadmin v1.20

+

Administracijski program

+

+

Namjena

+

+Program je namijenjen za jednostavnu administraciju +UNIX raèunala, prvenstveno osobama koje nisu u potpunosti ovladale +potrebnim znanjima, ali imaju potrebu za nekim osnovnim operacijama.
+Moguæe je izvesti slijedeæe operacije: + + +Dodavanje korisnika
+Brisanje korisnika
+Promjena lozinke korisnika
+Promjena quote korisnika
+Otvaranje nove grupe
+Brisanje grupe
+Dodavanje korisnika u grupu
+Brisanje korisnika iz grupe
+Otvaranje direktorija za rad grupe
+Brisanje direktorija za rad grupe
+Zaustavljanje i ga¹enje raèunala
+
+

+

Kratki opis

+

+Jedan od osnovnih zahtjeva u izradi ovog programa je sigurnost stroja +na kojem se izvodi. S obzirom na potrebne funkcije, program se izvodi +sa superkorisnièkim ovlastima, ali ih se li¹ava èim mu nisu +neophodne. Na taj naèin se smanjuje opasnost od zlouporabe. Osim toga, +izvoðenje programa je moguæe samo sa sistemske konzole raèunala (osim +u sluèaju kad ga pokreæe superkorisnik). Program provjerava sve operacije +zadane od korisnika i odbija izvr¹iti one koje bi naru¹ile +integritet raèunala odn. operacionog sustava. +

+Svaka uspje¹na operacija se bilje¾i u za to predviðenu log datoteku. +Uz opis izvoðene operacije, u ovoj datoteci se mo¾e naæi i toèno vrijeme +izvoðenja te svi proslijeðeni parametri. Za sluèaj da se programom +koristi vi¹e osoba, program bilje¾i i svako svoje pokretanje +(i izla¾enje) sa imenom osobe koja ga je pokrenula (ukoliko je start +bio uspje¹an). +

+Kontrola pristupa se vr¹i preko kontrolne datoteke u kojoj su +popisane osobe koje imaju pravo izvr¹avanja programa. Program +se mo¾e izvoditi na slijedeæim platformama: +

    +
  • Solaris 2.4 +
  • OSF/1 3.0 +
  • Ultrix 4.2 +
+Naravno, podr¾ane su i vi¹e inaèice navedenih operacionih sustava. +

+Program je izveden u programskom jeziku C. +Na OSF/1 i Ultrix OS koristi i po èetiri pomoæne skripte (raðene za +/bin/sh ljusku), +koje su izvedene iz sistemskih skripti iste namjene, ali im je poveæana +sigurnost kod uporabe. Sve verzije se kompiliraju iz istog izvornog +koda (sourcea). S programom dolaze upute za uporabu, te program za +instaliranje. +

+

Instalacija

+

+Arhiva sa svim potrebnim dijelovima programa mo¾e se naæi na raèunalu +bagan.srce.hr (IP adresa 161.53.2.66) u direktorijima: +

    +
  • /export/ftp/solaris2/SRCE/ +
  • /export/ftp/osf1/SRCE/ +
  • /export/ftp/ultrix/SRCE/ +
+Naziv arhive je sysadmin-1.20.tar, +a uz nju ide i pripadajuæi program za instalaciju naziva sysadmin-1.20.inst. +

+Kontrolne sume ovih datoteka su: +

+MD5 (sysadmin-1.20.tar) = d45808f333b18395fbb318e9bf6dc4c2
+MD5 (sysadmin-1.20.inst) = 4c640319c988e5bbe4c1d6ab6b518063
+
+Arhive u sva tri direktorija su identiène i sadr¾e sve potrebne binarne +datoteke, za sve potrebne platforme te izvorni kod programa. Ovakav +razmje¹taj je odabran iskljuèivo zbog jednostavnosti pronala¾enja +arhiva. +

+Preporuèeni naèin instalacije je pokretanje instalacijske skripte, +koja se sama brine za otpakiravanje arhive, prepoznavanje platforme +(OS-a) i razmje¹taj datoteka, koji se pone¹to razlikuje +na razlièitim operacionim sustavima: +

    +
  • sysadmin izvr¹ni program instalira se kao /usr/bin/sysadmin +(sve platforme) +
  • online priruènik se pronalazi kao /etc/sysadm.man +(sve platforme) +
  • pomoæni programi se nalaze u /usr/sbin direktoriju +(OSF/1), odn. /usr/etc direktoriju +(Ultrix) +
+Imena pomoænih programa su: sysadm.addgroup, sysadm.adduser, sysadm.removegroup, +sysadm.removeuser (sysadm.*). +

+Solaris OS ne zahtijeva pomoæne programe! +

+Primjer instalacije: +

+# cd /tmp
+# ftp 161.53.2.66
+Connected to 161.53.2.66.
+220 bagan FTP server (Version wu-2.4-ci(5) Fri Apr 26 13:03:49 MET DST 1996) ready.
+Name (161.53.2.66:zcalusic):
+331 Password required for zcalusic.
+Password:
+230 User zcalusic logged in.
+ftp> cd /export/ftp/ultrix/SRCE
+250 CWD command successful.
+ftp> bi
+200 Type set to I.
+ftp> prompt
+Interactive mode off.
+ftp> mget sysadmin*
+200 PORT command successful.
+150 Opening BINARY mode data connection for sysadmin-1.20.inst (1497 bytes).
+226 Transfer complete.
+local: sysadmin-1.20.inst remote: sysadmin-1.20.inst
+1497 bytes received in 0.1 seconds (14 Kbytes/s)
+200 PORT command successful.
+150 Opening BINARY mode data connection for sysadmin-1.20.tar (256000 bytes).
+226 Transfer complete.
+local: sysadmin-1.20.tar remote: sysadmin-1.20.tar
+256000 bytes received in 0.7 seconds (3.6e+02 Kbytes/s)
+ftp> quit
+221 Goodbye.
+# chmod +x sysadmin-1.20.inst
+# ./sysadmin-1.20.inst
+Instalacija sysadmin programa v1.20 na Ultrix platformu...
+...
+
+Nakon uspje¹nog instaliranja, program za instalaciju bri¹e +arhivu i samog sebe, te ispisuje poruku: +
+Za provjeru instalacije, dodaj login srce (SRCE Admin)!
+Ne zaboravi kreirati datoteku /etc/adminusers (root, 600)!
+
+U datoteku /etc/adminusers potrebno +je unijeti korisnièka imena osoba koje imaju pravo pokretanja programa. +Svakog korisnika treba unijeti u zasebnu liniju ove datoteke. Ukoliko +linija poèinje s znakom '#', +program smatra da smo unijeli komentar i zanemaruje ostatak linije. +

+Datoteka za logiranje mo¾e se pronaæi kao /var/adm/adminlog. +Ukoliko ne postoji, biti æe kreirana kod prvog pokretanja programa. +

+Ove dvije specijalne datoteke èitati i mijenjati mo¾e samo superkorisnik, +a program se kod svakog pokretanja brine da dozvole i ostanu takvima. +

+

O autoru

+

+Mentor projekta je Dobri¹a Dobreniæ.
+Autor programa je Zlatko Èalu¹iæ. +

+Upute priredio Zlatko Èalu¹iæ <zcalusic@srce.hr>
+Last modified: Fri Dec 20 01:25:31 MET 1996 + + + diff --git a/test.c b/test.c new file mode 100644 index 0000000..befe555 --- /dev/null +++ b/test.c @@ -0,0 +1,28 @@ +#include +#include +#include +#include + +#define MAXDIR (1024) + +int main(void) +{ + struct passwd *pwd; + struct dqblk qval; +#if defined(__SVR4) + struct quotctl qstr; + struct stat statbuf; +#elif defined(ultrix) + struct stat statbuf; +#elif defined(__linux__) + struct stat statbuf; + struct mntent *mntp; + FILE *fp; + int dev; + char devname[MAXDIR], greska[MAXDIR]; + devname[0] = '\0'; +#endif + + int soft, hard; + return 0; +} \ No newline at end of file diff --git a/users b/users new file mode 100644 index 0000000..e69de29 diff --git a/version.h b/version.h new file mode 100644 index 0000000..446a90d --- /dev/null +++ b/version.h @@ -0,0 +1,4 @@ +#ifndef VERSION_H + #define VERSION_H + #define VERSION "v1.25.1, Fri, 30 May 2003 11:26:24 +0200" +#endif -- 1.7.10.4