From: Ivan Rako Date: Wed, 20 May 2009 14:46:56 +0000 (+0200) Subject: prva verzija za lenny X-Git-Tag: debian/1.27.squeeze1~12 X-Git-Url: http://ftp.carnet.hr/carnet-debian/scm?a=commitdiff_plain;h=0f94b0c4d6f67ee6bd36a0d679396482c5689264;p=sysadmin-cn.git prva verzija za lenny --- 0f94b0c4d6f67ee6bd36a0d679396482c5689264 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