aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile4
-rw-r--r--include/usage.h16
-rw-r--r--libpwdgrp/Makefile30
-rw-r--r--libpwdgrp/Makefile.in35
-rw-r--r--libpwdgrp/__getgrent.c204
-rw-r--r--libpwdgrp/__getpwent.c115
-rw-r--r--libpwdgrp/fgetgrent.c35
-rw-r--r--libpwdgrp/fgetpwent.c35
-rw-r--r--libpwdgrp/getgrgid.c44
-rw-r--r--libpwdgrp/getgrnam.c50
-rw-r--r--libpwdgrp/getpw.c47
-rw-r--r--libpwdgrp/getpwnam.c51
-rw-r--r--libpwdgrp/getpwuid.c44
-rw-r--r--libpwdgrp/grent.c54
-rw-r--r--libpwdgrp/initgroups.c115
-rw-r--r--libpwdgrp/putpwent.c39
-rw-r--r--libpwdgrp/pwent.c58
-rw-r--r--libpwdgrp/setgroups.c42
-rw-r--r--libpwdgrp/shadow.c302
-rw-r--r--loginutils/Makefile30
-rw-r--r--loginutils/Makefile.in45
-rw-r--r--loginutils/addgroup.c168
-rw-r--r--loginutils/adduser.c352
-rw-r--r--loginutils/config.in25
-rw-r--r--loginutils/deluser.c183
-rw-r--r--loginutils/getty.c1157
-rw-r--r--loginutils/login.c459
-rw-r--r--loginutils/su.c167
-rw-r--r--loginutils/tinylogin.c209
-rw-r--r--loginutils/tinylogin.h10
30 files changed, 4123 insertions, 2 deletions
diff --git a/Makefile b/Makefile
index f86ebedf7..dc299cded 100644
--- a/Makefile
+++ b/Makefile
@@ -22,8 +22,8 @@ include $(TOPDIR).config
22include $(TOPDIR)Rules.mak 22include $(TOPDIR)Rules.mak
23SUBDIRS:=applets archival archival/libunarchive console-tools \ 23SUBDIRS:=applets archival archival/libunarchive console-tools \
24 editors fileutils findutils init miscutils modutils networking \ 24 editors fileutils findutils init miscutils modutils networking \
25 procps pwd_grp pwd_grp/libpwd_grp shell shellutils sysklogd \ 25 procps loginutils shell shellutils sysklogd \
26 textutils util-linux libbb 26 textutils util-linux libbb libpwdgrp
27 27
28all: do-it-all 28all: do-it-all
29 29
diff --git a/include/usage.h b/include/usage.h
index 823d95296..08ee00d77 100644
--- a/include/usage.h
+++ b/include/usage.h
@@ -978,6 +978,15 @@
978#define logger_example_usage \ 978#define logger_example_usage \
979 "$ logger "hello"\n" 979 "$ logger "hello"\n"
980 980
981#define login_trivial_usage \
982 "[OPTION]... [username] [ENV=VAR ...]"
983#define login_full_usage \
984 "Begin a new session on the system\n\n" \
985 "Options:\n" \
986 "\t-f\tDo not authenticate (user already authenticated)\n" \
987 "\t-h\tName of the remote host for this login.\n" \
988 "\t-p\tPreserve environment."
989
981#define logname_trivial_usage \ 990#define logname_trivial_usage \
982 "" 991 ""
983#define logname_full_usage \ 992#define logname_full_usage \
@@ -1570,6 +1579,13 @@
1570 "\n\t-g\t\tprint in stty-readable form" \ 1579 "\n\t-g\t\tprint in stty-readable form" \
1571 "\n\t[SETTING]\tsee manpage" 1580 "\n\t[SETTING]\tsee manpage"
1572 1581
1582#define su_trivial_usage \
1583 "[OPTION]... [-] [username]"
1584#define su_full_usage \
1585 "Change user id or become root.\n" \
1586 "Options:\n" \
1587 "\t-p\tPreserve environment"
1588
1573#define swapoff_trivial_usage \ 1589#define swapoff_trivial_usage \
1574 "[OPTION] [DEVICE]" 1590 "[OPTION] [DEVICE]"
1575#define swapoff_full_usage \ 1591#define swapoff_full_usage \
diff --git a/libpwdgrp/Makefile b/libpwdgrp/Makefile
new file mode 100644
index 000000000..2708027ec
--- /dev/null
+++ b/libpwdgrp/Makefile
@@ -0,0 +1,30 @@
1# Makefile for busybox
2#
3# Copyright (C) 1999-2002 Erik Andersen <andersee@debian.org>
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 2 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13# General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program; if not, write to the Free Software
17# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18#
19
20TOPDIR:= ../
21LIBPWDGRP_DIR:=./
22include $(TOPDIR).config
23include $(TOPDIR)Rules.mak
24include Makefile.in
25all: $(libraries-y)
26-include $(TOPDIR).depend
27
28clean:
29 rm -f *.o *.a $(AR_TARGET)
30
diff --git a/libpwdgrp/Makefile.in b/libpwdgrp/Makefile.in
new file mode 100644
index 000000000..970457112
--- /dev/null
+++ b/libpwdgrp/Makefile.in
@@ -0,0 +1,35 @@
1# Makefile for busybox
2#
3# Copyright (C) 1999-2002 Erik Andersen <andersee@debian.org>
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 2 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13# General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program; if not, write to the Free Software
17# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18#
19
20LIBPWDGRP_AR:=libpwdgrp.a
21ifndef $(LIBPWDGRP_DIR)
22LIBPWDGRP_DIR:=$(TOPDIR)libpwdgrp/
23endif
24
25LIBPWDGRP-y:=
26LIBPWDGRP-$(CONFIG_USE_BB_PWD_GRP) += __getgrent.o __getgrent.o __getpwent.o\
27 fgetgrent.o fgetpwent.o getgrgid.o getgrnam.o getpw.o getpwnam.o \
28 getpwuid.o grent.o initgroups.o putpwent.o pwent.o setgroups.o
29LIBPWDGRP-$(CONFIG_USE_BB_SHADOW) += shadow.o
30
31libraries-y+=$(LIBPWDGRP_DIR)$(LIBPWDGRP_AR)
32
33$(LIBPWDGRP_DIR)$(LIBPWDGRP_AR): $(patsubst %,$(LIBPWDGRP_DIR)%, $(LIBPWDGRP-y))
34 $(AR) -ro $@ $(patsubst %,$(LIBPWDGRP_DIR)%, $(LIBPWDGRP-y))
35
diff --git a/libpwdgrp/__getgrent.c b/libpwdgrp/__getgrent.c
new file mode 100644
index 000000000..571da3fc3
--- /dev/null
+++ b/libpwdgrp/__getgrent.c
@@ -0,0 +1,204 @@
1/*
2 * __getgrent.c - This file is part of the libc-8086/grp package for ELKS,
3 * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the Free
17 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *
19 */
20
21#include "busybox.h"
22
23#include <unistd.h>
24#include <stdlib.h>
25#include <string.h>
26#include "grp.h"
27
28/*
29 * Define GR_SCALE_DYNAMIC if you want grp to dynamically scale its read buffer
30 * so that lines of any length can be used. On very very small systems,
31 * you may want to leave this undefined becasue it will make the grp functions
32 * somewhat larger (because of the inclusion of malloc and the code necessary).
33 * On larger systems, you will want to define this, because grp will _not_
34 * deal with long lines gracefully (they will be skipped).
35 */
36#undef GR_SCALE_DYNAMIC
37
38#ifndef GR_SCALE_DYNAMIC
39/*
40 * If scaling is not dynamic, the buffers will be statically allocated, and
41 * maximums must be chosen. GR_MAX_LINE_LEN is the maximum number of
42 * characters per line in the group file. GR_MAX_MEMBERS is the maximum
43 * number of members of any given group.
44 */
45#define GR_MAX_LINE_LEN 128
46/* GR_MAX_MEMBERS = (GR_MAX_LINE_LEN-(24+3+6))/9 */
47#define GR_MAX_MEMBERS 11
48
49#endif /* !GR_SCALE_DYNAMIC */
50
51
52/*
53 * Define GR_DYNAMIC_GROUP_LIST to make initgroups() dynamically allocate
54 * space for it's GID array before calling setgroups(). This is probably
55 * unnecessary scalage, so it's undefined by default.
56 */
57#undef GR_DYNAMIC_GROUP_LIST
58
59#ifndef GR_DYNAMIC_GROUP_LIST
60/*
61 * GR_MAX_GROUPS is the size of the static array initgroups() uses for
62 * its static GID array if GR_DYNAMIC_GROUP_LIST isn't defined.
63 */
64#define GR_MAX_GROUPS 64
65
66#endif /* !GR_DYNAMIC_GROUP_LIST */
67
68
69/*
70 * This is the core group-file read function. It behaves exactly like
71 * getgrent() except that it is passed a file descriptor. getgrent()
72 * is just a wrapper for this function.
73 */
74struct group *__getgrent(int grp_fd)
75{
76#ifndef GR_SCALE_DYNAMIC
77 static char line_buff[GR_MAX_LINE_LEN];
78 static char *members[GR_MAX_MEMBERS];
79#else
80 static char *line_buff = NULL;
81 static char **members = NULL;
82 short line_index;
83 short buff_size;
84#endif
85 static struct group group;
86 register char *ptr;
87 char *field_begin;
88 short member_num;
89 char *endptr;
90 int line_len;
91
92
93 /* We use the restart label to handle malformatted lines */
94 restart:
95#ifdef GR_SCALE_DYNAMIC
96 line_index = 0;
97 buff_size = 256;
98#endif
99
100#ifndef GR_SCALE_DYNAMIC
101 /* Read the line into the static buffer */
102 if ((line_len = read(grp_fd, line_buff, GR_MAX_LINE_LEN)) <= 0)
103 return NULL;
104 field_begin = strchr(line_buff, '\n');
105 if (field_begin != NULL)
106 lseek(grp_fd, (long) (1 + field_begin - (line_buff + line_len)),
107 SEEK_CUR);
108 else { /* The line is too long - skip it :-\ */
109
110 do {
111 if ((line_len = read(grp_fd, line_buff, GR_MAX_LINE_LEN)) <= 0)
112 return NULL;
113 } while (!(field_begin = strchr(line_buff, '\n')));
114 lseek(grp_fd, (long) ((field_begin - line_buff) - line_len + 1),
115 SEEK_CUR);
116 goto restart;
117 }
118 if (*line_buff == '#' || *line_buff == ' ' || *line_buff == '\n' ||
119 *line_buff == '\t')
120 goto restart;
121 *field_begin = '\0';
122
123#else /* !GR_SCALE_DYNAMIC */
124 line_buff = realloc(line_buff, buff_size);
125 while (1) {
126 if ((line_len = read(grp_fd, line_buff + line_index,
127 buff_size - line_index)) <= 0)
128 return NULL;
129 field_begin = strchr(line_buff, '\n');
130 if (field_begin != NULL) {
131 lseek(grp_fd,
132 (long) (1 + field_begin -
133 (line_len + line_index + line_buff)), SEEK_CUR);
134 *field_begin = '\0';
135 if (*line_buff == '#' || *line_buff == ' '
136 || *line_buff == '\n' || *line_buff == '\t')
137 goto restart;
138 break;
139 } else { /* Allocate some more space */
140
141 line_index = buff_size;
142 buff_size += 256;
143 line_buff = realloc(line_buff, buff_size);
144 }
145 }
146#endif /* GR_SCALE_DYNAMIC */
147
148 /* Now parse the line */
149 group.gr_name = line_buff;
150 ptr = strchr(line_buff, ':');
151 if (ptr == NULL)
152 goto restart;
153 *ptr++ = '\0';
154
155 group.gr_passwd = ptr;
156 ptr = strchr(ptr, ':');
157 if (ptr == NULL)
158 goto restart;
159 *ptr++ = '\0';
160
161 field_begin = ptr;
162 ptr = strchr(ptr, ':');
163 if (ptr == NULL)
164 goto restart;
165 *ptr++ = '\0';
166
167 group.gr_gid = (gid_t) strtoul(field_begin, &endptr, 10);
168 if (*endptr != '\0')
169 goto restart;
170
171 member_num = 0;
172 field_begin = ptr;
173
174#ifndef GR_SCALE_DYNAMIC
175 while ((ptr = strchr(ptr, ',')) != NULL) {
176 *ptr = '\0';
177 ptr++;
178 members[member_num] = field_begin;
179 field_begin = ptr;
180 member_num++;
181 }
182 if (*field_begin == '\0')
183 members[member_num] = NULL;
184 else {
185 members[member_num] = field_begin;
186 members[member_num + 1] = NULL;
187 }
188#else /* !GR_SCALE_DYNAMIC */
189 if (members != NULL)
190 free(members);
191 members = (char **) malloc((member_num + 1) * sizeof(char *));
192 for ( ; field_begin && *field_begin != '\0'; field_begin = ptr) {
193 if ((ptr = strchr(field_begin, ',')) != NULL)
194 *ptr++ = '\0';
195 members[member_num++] = field_begin;
196 members = (char **) realloc(members,
197 (member_num + 1) * sizeof(char *));
198 }
199 members[member_num] = NULL;
200#endif /* GR_SCALE_DYNAMIC */
201
202 group.gr_mem = members;
203 return &group;
204}
diff --git a/libpwdgrp/__getpwent.c b/libpwdgrp/__getpwent.c
new file mode 100644
index 000000000..e406b8824
--- /dev/null
+++ b/libpwdgrp/__getpwent.c
@@ -0,0 +1,115 @@
1/*
2 * __getpwent.c - This file is part of the libc-8086/pwd package for ELKS,
3 * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the Free
17 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *
19 */
20
21#include "busybox.h"
22
23#include <stdlib.h>
24#include <unistd.h>
25#include <string.h>
26#include <fcntl.h>
27#include "pwd.h"
28
29#define PWD_BUFFER_SIZE 256
30
31/* This isn't as flash as my previous version -- it doesn't dynamically
32 scale down the gecos on too-long lines, but it also makes fewer syscalls,
33 so it's probably nicer. Write me if you want the old version. Maybe I
34 should include it as a build-time option... ?
35 -Nat <ndf@linux.mit.edu> */
36
37struct passwd *__getpwent(int pwd_fd)
38{
39 static char line_buff[PWD_BUFFER_SIZE];
40 static struct passwd passwd;
41 char *field_begin;
42 char *endptr;
43 char *gid_ptr=NULL;
44 char *uid_ptr=NULL;
45 int line_len;
46 int i;
47
48 /* We use the restart label to handle malformatted lines */
49 restart:
50 /* Read the passwd line into the static buffer using a minimal of
51 syscalls. */
52 if ((line_len = read(pwd_fd, line_buff, PWD_BUFFER_SIZE)) <= 0)
53 return NULL;
54 field_begin = strchr(line_buff, '\n');
55 if (field_begin != NULL)
56 lseek(pwd_fd, (long) (1 + field_begin - (line_buff + line_len)),
57 SEEK_CUR);
58 else { /* The line is too long - skip it. :-\ */
59
60 do {
61 if ((line_len = read(pwd_fd, line_buff, PWD_BUFFER_SIZE)) <= 0)
62 return NULL;
63 } while (!(field_begin = strchr(line_buff, '\n')));
64 lseek(pwd_fd, (long) (field_begin - line_buff) - line_len + 1,
65 SEEK_CUR);
66 goto restart;
67 }
68 if (*line_buff == '#' || *line_buff == ' ' || *line_buff == '\n' ||
69 *line_buff == '\t')
70 goto restart;
71 *field_begin = '\0';
72
73 /* We've read the line; now parse it. */
74 field_begin = line_buff;
75 for (i = 0; i < 7; i++) {
76 switch (i) {
77 case 0:
78 passwd.pw_name = field_begin;
79 break;
80 case 1:
81 passwd.pw_passwd = field_begin;
82 break;
83 case 2:
84 uid_ptr = field_begin;
85 break;
86 case 3:
87 gid_ptr = field_begin;
88 break;
89 case 4:
90 passwd.pw_gecos = field_begin;
91 break;
92 case 5:
93 passwd.pw_dir = field_begin;
94 break;
95 case 6:
96 passwd.pw_shell = field_begin;
97 break;
98 }
99 if (i < 6) {
100 field_begin = strchr(field_begin, ':');
101 if (field_begin == NULL)
102 goto restart;
103 *field_begin++ = '\0';
104 }
105 }
106 passwd.pw_gid = (gid_t) strtoul(gid_ptr, &endptr, 10);
107 if (*endptr != '\0')
108 goto restart;
109
110 passwd.pw_uid = (uid_t) strtoul(uid_ptr, &endptr, 10);
111 if (*endptr != '\0')
112 goto restart;
113
114 return &passwd;
115}
diff --git a/libpwdgrp/fgetgrent.c b/libpwdgrp/fgetgrent.c
new file mode 100644
index 000000000..c5d63e05f
--- /dev/null
+++ b/libpwdgrp/fgetgrent.c
@@ -0,0 +1,35 @@
1/*
2 * fgetgrent.c - This file is part of the libc-8086/grp package for ELKS,
3 * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the Free
17 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *
19 */
20
21#include "busybox.h"
22
23#include <stdio.h>
24#include <errno.h>
25#include "grp.h"
26
27struct group *fgetgrent(FILE * file)
28{
29 if (file == NULL) {
30 errno = EINTR;
31 return NULL;
32 }
33
34 return __getgrent(fileno(file));
35}
diff --git a/libpwdgrp/fgetpwent.c b/libpwdgrp/fgetpwent.c
new file mode 100644
index 000000000..6537600ff
--- /dev/null
+++ b/libpwdgrp/fgetpwent.c
@@ -0,0 +1,35 @@
1/*
2 * fgetpwent.c - This file is part of the libc-8086/pwd package for ELKS,
3 * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the Free
17 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *
19 */
20
21#include "busybox.h"
22
23#include <errno.h>
24#include <stdio.h>
25#include "pwd.h"
26
27struct passwd *fgetpwent(FILE * file)
28{
29 if (file == NULL) {
30 errno = EINTR;
31 return NULL;
32 }
33
34 return __getpwent(fileno(file));
35}
diff --git a/libpwdgrp/getgrgid.c b/libpwdgrp/getgrgid.c
new file mode 100644
index 000000000..e70346a77
--- /dev/null
+++ b/libpwdgrp/getgrgid.c
@@ -0,0 +1,44 @@
1/*
2 * getgrgid.c - This file is part of the libc-8086/grp package for ELKS,
3 * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the Free
17 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *
19 */
20
21#include "busybox.h"
22
23#include <sys/types.h>
24#include <unistd.h>
25#include <fcntl.h>
26#include "grp.h"
27
28struct group *getgrgid(const gid_t gid)
29{
30 struct group *group;
31 int grp_fd;
32
33 if ((grp_fd = open("/etc/group", O_RDONLY)) < 0)
34 return NULL;
35
36 while ((group = __getgrent(grp_fd)) != NULL)
37 if (group->gr_gid == gid) {
38 close(grp_fd);
39 return group;
40 }
41
42 close(grp_fd);
43 return NULL;
44}
diff --git a/libpwdgrp/getgrnam.c b/libpwdgrp/getgrnam.c
new file mode 100644
index 000000000..62b2b26ca
--- /dev/null
+++ b/libpwdgrp/getgrnam.c
@@ -0,0 +1,50 @@
1/*
2 * getgrnam.c - This file is part of the libc-8086/grp package for ELKS,
3 * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the Free
17 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *
19 */
20
21#include "busybox.h"
22
23#include <unistd.h>
24#include <string.h>
25#include <errno.h>
26#include <fcntl.h>
27#include "grp.h"
28
29struct group *getgrnam(const char *name)
30{
31 int grp_fd;
32 struct group *group;
33
34 if (name == NULL) {
35 errno = EINVAL;
36 return NULL;
37 }
38
39 if ((grp_fd = open("/etc/group", O_RDONLY)) < 0)
40 return NULL;
41
42 while ((group = __getgrent(grp_fd)) != NULL)
43 if (!strcmp(group->gr_name, name)) {
44 close(grp_fd);
45 return group;
46 }
47
48 close(grp_fd);
49 return NULL;
50}
diff --git a/libpwdgrp/getpw.c b/libpwdgrp/getpw.c
new file mode 100644
index 000000000..ca11188aa
--- /dev/null
+++ b/libpwdgrp/getpw.c
@@ -0,0 +1,47 @@
1/*
2 * getpw.c - This file is part of the libc-8086/pwd package for ELKS,
3 * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the Free
17 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *
19 */
20
21#include "busybox.h"
22
23#include <sys/types.h>
24#include <errno.h>
25#include <stdio.h>
26#include "pwd.h"
27
28int getpw(uid_t uid, char *buf)
29{
30 struct passwd *passwd;
31
32 if (buf == NULL) {
33 errno = EINVAL;
34 return -1;
35 }
36 if ((passwd = getpwuid(uid)) == NULL)
37 return -1;
38
39 if (sprintf (buf, "%s:%s:%u:%u:%s:%s:%s", passwd->pw_name, passwd->pw_passwd,
40 passwd->pw_gid, passwd->pw_uid, passwd->pw_gecos, passwd->pw_dir,
41 passwd->pw_shell) < 0) {
42 errno = ENOBUFS;
43 return -1;
44 }
45
46 return 0;
47}
diff --git a/libpwdgrp/getpwnam.c b/libpwdgrp/getpwnam.c
new file mode 100644
index 000000000..88a31f8c2
--- /dev/null
+++ b/libpwdgrp/getpwnam.c
@@ -0,0 +1,51 @@
1/*
2 * getpwnam.c - This file is part of the libc-8086/pwd package for ELKS,
3 * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the Free
17 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *
19 */
20
21#include "busybox.h"
22
23#include <unistd.h>
24#include <string.h>
25#include <errno.h>
26#include <fcntl.h>
27#include "pwd.h"
28
29
30struct passwd *getpwnam(const char *name)
31{
32 int passwd_fd;
33 struct passwd *passwd;
34
35 if (name == NULL) {
36 errno = EINVAL;
37 return NULL;
38 }
39
40 if ((passwd_fd = open("/etc/passwd", O_RDONLY)) < 0)
41 return NULL;
42
43 while ((passwd = __getpwent(passwd_fd)) != NULL)
44 if (!strcmp(passwd->pw_name, name)) {
45 close(passwd_fd);
46 return passwd;
47 }
48
49 close(passwd_fd);
50 return NULL;
51}
diff --git a/libpwdgrp/getpwuid.c b/libpwdgrp/getpwuid.c
new file mode 100644
index 000000000..776ed12da
--- /dev/null
+++ b/libpwdgrp/getpwuid.c
@@ -0,0 +1,44 @@
1/*
2 * getpwuid.c - This file is part of the libc-8086/pwd package for ELKS,
3 * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the Free
17 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *
19 */
20
21#include "busybox.h"
22
23#include <stdlib.h>
24#include <unistd.h>
25#include <fcntl.h>
26#include "pwd.h"
27
28struct passwd *getpwuid(uid_t uid)
29{
30 int passwd_fd;
31 struct passwd *passwd;
32
33 if ((passwd_fd = open("/etc/passwd", O_RDONLY)) < 0)
34 return NULL;
35
36 while ((passwd = __getpwent(passwd_fd)) != NULL)
37 if (passwd->pw_uid == uid) {
38 close(passwd_fd);
39 return passwd;
40 }
41
42 close(passwd_fd);
43 return NULL;
44}
diff --git a/libpwdgrp/grent.c b/libpwdgrp/grent.c
new file mode 100644
index 000000000..5b1cb6823
--- /dev/null
+++ b/libpwdgrp/grent.c
@@ -0,0 +1,54 @@
1/*
2 * grent.c - This file is part of the libc-8086/grp package for ELKS,
3 * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the Free
17 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *
19 */
20
21/*
22 * setgrent(), endgrent(), and getgrent() are mutually-dependent functions,
23 * so they are all included in the same object file, and thus all linked
24 * in together.
25 */
26
27#include "busybox.h"
28
29#include <unistd.h>
30#include <fcntl.h>
31#include "grp.h"
32
33static int grp_fd = -1;
34
35void setgrent(void)
36{
37 if (grp_fd != -1)
38 close(grp_fd);
39 grp_fd = open("/etc/group", O_RDONLY);
40}
41
42void endgrent(void)
43{
44 if (grp_fd != -1)
45 close(grp_fd);
46 grp_fd = -1;
47}
48
49struct group *getgrent(void)
50{
51 if (grp_fd == -1)
52 return NULL;
53 return __getgrent(grp_fd);
54}
diff --git a/libpwdgrp/initgroups.c b/libpwdgrp/initgroups.c
new file mode 100644
index 000000000..9b5dcbcb2
--- /dev/null
+++ b/libpwdgrp/initgroups.c
@@ -0,0 +1,115 @@
1/*
2 * initgroups.c - This file is part of the libc-8086/grp package for ELKS,
3 * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the Free
17 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *
19 */
20
21#include "busybox.h"
22
23#include <unistd.h>
24#include <string.h>
25#include <fcntl.h>
26#include "grp.h"
27
28/*
29 * Define GR_SCALE_DYNAMIC if you want grp to dynamically scale its read buffer
30 * so that lines of any length can be used. On very very small systems,
31 * you may want to leave this undefined becasue it will make the grp functions
32 * somewhat larger (because of the inclusion of malloc and the code necessary).
33 * On larger systems, you will want to define this, because grp will _not_
34 * deal with long lines gracefully (they will be skipped).
35 */
36#undef GR_SCALE_DYNAMIC
37
38#ifndef GR_SCALE_DYNAMIC
39/*
40 * If scaling is not dynamic, the buffers will be statically allocated, and
41 * maximums must be chosen. GR_MAX_LINE_LEN is the maximum number of
42 * characters per line in the group file. GR_MAX_MEMBERS is the maximum
43 * number of members of any given group.
44 */
45#define GR_MAX_LINE_LEN 128
46/* GR_MAX_MEMBERS = (GR_MAX_LINE_LEN-(24+3+6))/9 */
47#define GR_MAX_MEMBERS 11
48
49#endif /* !GR_SCALE_DYNAMIC */
50
51
52/*
53 * Define GR_DYNAMIC_GROUP_LIST to make initgroups() dynamically allocate
54 * space for it's GID array before calling setgroups(). This is probably
55 * unnecessary scalage, so it's undefined by default.
56 */
57#undef GR_DYNAMIC_GROUP_LIST
58
59#ifndef GR_DYNAMIC_GROUP_LIST
60/*
61 * GR_MAX_GROUPS is the size of the static array initgroups() uses for
62 * its static GID array if GR_DYNAMIC_GROUP_LIST isn't defined.
63 */
64#define GR_MAX_GROUPS 64
65
66#endif /* !GR_DYNAMIC_GROUP_LIST */
67
68int initgroups(__const char *user, gid_t gid)
69{
70 register struct group *group;
71
72#ifndef GR_DYNAMIC_GROUP_LIST
73 gid_t group_list[GR_MAX_GROUPS];
74#else
75 gid_t *group_list = NULL;
76#endif
77 register char **tmp_mem;
78 int num_groups;
79 int grp_fd;
80
81
82 if ((grp_fd = open("/etc/group", O_RDONLY)) < 0)
83 return -1;
84
85 num_groups = 0;
86#ifdef GR_DYNAMIC_GROUP_LIST
87 group_list = (gid_t *) realloc(group_list, 1);
88#endif
89 group_list[num_groups] = gid;
90#ifndef GR_DYNAMIC_GROUP_LIST
91 while (num_groups < GR_MAX_GROUPS &&
92 (group = __getgrent(grp_fd)) != NULL)
93#else
94 while ((group = __getgrent(grp_fd)) != NULL)
95#endif
96 {
97 if (group->gr_gid != gid);
98 {
99 tmp_mem = group->gr_mem;
100 while (*tmp_mem != NULL) {
101 if (!strcmp(*tmp_mem, user)) {
102 num_groups++;
103#ifdef GR_DYNAMIC_GROUP_LIST
104 group_list = (gid_t *) realloc(group_list, num_groups *
105 sizeof(gid_t *));
106#endif
107 group_list[num_groups] = group->gr_gid;
108 }
109 tmp_mem++;
110 }
111 }
112 }
113 close(grp_fd);
114 return setgroups(num_groups, group_list);
115}
diff --git a/libpwdgrp/putpwent.c b/libpwdgrp/putpwent.c
new file mode 100644
index 000000000..88dffc952
--- /dev/null
+++ b/libpwdgrp/putpwent.c
@@ -0,0 +1,39 @@
1/*
2 * putpwent.c - This file is part of the libc-8086/pwd package for ELKS,
3 * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the Free
17 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *
19 */
20
21#include "busybox.h"
22
23#include <stdio.h>
24#include <errno.h>
25#include "pwd.h"
26
27int putpwent(const struct passwd *passwd, FILE * f)
28{
29 if (passwd == NULL || f == NULL) {
30 errno = EINVAL;
31 return -1;
32 }
33 if (fprintf (f, "%s:%s:%u:%u:%s:%s:%s\n", passwd->pw_name, passwd->pw_passwd,
34 passwd->pw_gid, passwd->pw_uid, passwd->pw_gecos, passwd->pw_dir,
35 passwd->pw_shell) < 0)
36 return -1;
37
38 return 0;
39}
diff --git a/libpwdgrp/pwent.c b/libpwdgrp/pwent.c
new file mode 100644
index 000000000..84bd6176b
--- /dev/null
+++ b/libpwdgrp/pwent.c
@@ -0,0 +1,58 @@
1/*
2 * pwent.c - This file is part of the libc-8086/pwd package for ELKS,
3 * Copyright (C) 1995, 1996 Nat Friedman <ndf@linux.mit.edu>.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the Free
17 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *
19 */
20
21#include "busybox.h"
22
23#include <unistd.h>
24#include <stdlib.h>
25#include <errno.h>
26#include "pwd.h"
27#include <fcntl.h>
28
29/*
30 * setpwent(), endpwent(), and getpwent() are included in the same object
31 * file, since one cannot be used without the other two, so it makes sense to
32 * link them all in together.
33 */
34
35/* file descriptor for the password file currently open */
36static int pw_fd = -1;
37
38void setpwent(void)
39{
40 if (pw_fd != -1)
41 close(pw_fd);
42
43 pw_fd = open("/etc/passwd", O_RDONLY);
44}
45
46void endpwent(void)
47{
48 if (pw_fd != -1)
49 close(pw_fd);
50 pw_fd = -1;
51}
52
53struct passwd *getpwent(void)
54{
55 if (pw_fd != -1)
56 return (__getpwent(pw_fd));
57 return NULL;
58}
diff --git a/libpwdgrp/setgroups.c b/libpwdgrp/setgroups.c
new file mode 100644
index 000000000..c9b86f016
--- /dev/null
+++ b/libpwdgrp/setgroups.c
@@ -0,0 +1,42 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Taken from the set of syscalls for uClibc
4 *
5 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
6 * <andersen@lineo.com>, <andersee@debian.org>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Library General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
16 * for more details.
17 *
18 * You should have received a copy of the GNU Library General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24#include "busybox.h"
25
26#include <errno.h>
27#include <unistd.h>
28#include <features.h>
29#include <sys/types.h>
30/* Kernel headers before 2.1.mumble need this on the Alpha to get
31 _syscall* defined. */
32#define __LIBRARY__
33#include <sys/syscall.h>
34#if __GNU_LIBRARY__ < 5
35/* This is needed for libc5 */
36#include <asm/unistd.h>
37#endif
38#include "grp.h"
39
40//#define __NR_setgroups 81
41_syscall2(int, setgroups, size_t, size, const gid_t *, list);
42
diff --git a/libpwdgrp/shadow.c b/libpwdgrp/shadow.c
new file mode 100644
index 000000000..6cf195e4a
--- /dev/null
+++ b/libpwdgrp/shadow.c
@@ -0,0 +1,302 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Copyright 1989 - 1994, Julianne Frances Haugh
4 * <jockgrrl@austin.rr.com>, <jfh@austin.ibm.com>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32/* TODO: fgetspent_r.c getspent_r.c getspnam_r.c sgetspent_r.c
33 * lckpwdf ulckpwdf
34 */
35
36#include "busybox.h"
37
38#include <stdio.h>
39#include <stdlib.h>
40#include <string.h>
41#include <unistd.h>
42
43#include "shadow.h"
44
45static FILE *shadow;
46static char spwbuf[BUFSIZ];
47static struct spwd spwd;
48
49#define FIELDS 9
50#define OFIELDS 5
51
52/* setspent - initialize access to shadow text and DBM files */
53void setspent(void)
54{
55 if (shadow) {
56 rewind(shadow);
57 } else {
58 if ((shadow = fopen("/etc/shadow", "r")) == NULL)
59 perror_msg_and_die("/etc/shadow");
60 }
61}
62
63/* endspent - terminate access to shadow text and DBM files */
64void endspent(void)
65{
66 if (shadow)
67 (void) fclose(shadow);
68 shadow = (FILE *) 0;
69}
70
71/* getspent - get a (struct spwd *) from the current shadow file */
72struct spwd *getspent(void)
73{
74 if (!shadow)
75 setspent();
76 return (fgetspent(shadow));
77}
78
79/* getspnam - get a shadow entry by name */
80struct spwd *getspnam(const char *name)
81{
82 struct spwd *sp;
83
84 if (!name || !strlen(name))
85 return NULL;
86
87 setspent();
88 while ((sp = getspent()) != NULL) {
89 if (strcmp(name, sp->sp_namp) == 0)
90 break;
91 }
92 endspent();
93 return (sp);
94}
95
96
97/* sgetspent - convert string in shadow file format to (struct spwd *) */
98/* returns NULL on error */
99struct spwd *sgetspent(const char *string)
100{
101 char *fields[FIELDS];
102 char *cp;
103 char *cpp;
104 int i;
105
106 /*
107 * Copy string to local buffer. It has to be tokenized and we
108 * have to do that to our private copy.
109 */
110
111 if (strlen(string) >= sizeof spwbuf)
112 /* return 0; */
113 return NULL;
114 strcpy(spwbuf, string);
115
116 if ((cp = strrchr(spwbuf, '\n')))
117 *cp = '\0';
118
119 /*
120 * Tokenize the string into colon separated fields. Allow up to
121 * FIELDS different fields.
122 */
123
124 for (cp = spwbuf, i = 0; *cp && i < FIELDS; i++) {
125 fields[i] = cp;
126 while (*cp && *cp != ':')
127 cp++;
128
129 if (*cp)
130 *cp++ = '\0';
131 }
132
133 /*
134 * It is acceptable for the last SVR4 field to be blank. This
135 * results in the loop being terminated early. In which case,
136 * we just make the last field be blank and be done with it.
137 */
138
139 if (i == (FIELDS - 1))
140 fields[i++] = cp;
141
142 if ((cp && *cp) || (i != FIELDS && i != OFIELDS))
143 /* return 0; */
144 return NULL;
145
146 /*
147 * Start populating the structure. The fields are all in
148 * static storage, as is the structure we pass back. If we
149 * ever see a name with '+' as the first character, we try
150 * to turn on NIS processing.
151 */
152
153 spwd.sp_namp = fields[0];
154 spwd.sp_pwdp = fields[1];
155
156 /*
157 * Get the last changed date. For all of the integer fields,
158 * we check for proper format. It is an error to have an
159 * incorrectly formatted number, unless we are using NIS.
160 */
161
162 if ((spwd.sp_lstchg = strtol(fields[2], &cpp, 10)) == 0 && *cpp) {
163 /* return 0; */
164 return NULL;
165 } else if (fields[2][0] == '\0')
166 spwd.sp_lstchg = -1;
167
168 /*
169 * Get the minimum period between password changes.
170 */
171
172 if ((spwd.sp_min = strtol(fields[3], &cpp, 10)) == 0 && *cpp) {
173 /* return 0; */
174 return NULL;
175 } else if (fields[3][0] == '\0')
176 spwd.sp_min = -1;
177
178 /*
179 * Get the maximum number of days a password is valid.
180 */
181
182 if ((spwd.sp_max = strtol(fields[4], &cpp, 10)) == 0 && *cpp) {
183 /* return 0; */
184 return NULL;
185 } else if (fields[4][0] == '\0')
186 spwd.sp_max = -1;
187
188 /*
189 * If there are only OFIELDS fields (this is a SVR3.2 /etc/shadow
190 * formatted file), initialize the other field members to -1.
191 */
192
193 if (i == OFIELDS) {
194 spwd.sp_warn = spwd.sp_inact = spwd.sp_expire = spwd.sp_flag = -1;
195
196 return &spwd;
197 }
198
199 /*
200 * The rest of the fields are mandatory for SVR4, but optional
201 * for anything else. However, if one is present the others
202 * must be as well.
203 */
204
205 /*
206 * Get the number of days of password expiry warning.
207 */
208
209 if ((spwd.sp_warn = strtol(fields[5], &cpp, 10)) == 0 && *cpp) {
210 /* return 0; */
211 return NULL;
212 } else if (fields[5][0] == '\0')
213 spwd.sp_warn = -1;
214
215 /*
216 * Get the number of days of inactivity before an account is
217 * disabled.
218 */
219
220 if ((spwd.sp_inact = strtol(fields[6], &cpp, 10)) == 0 && *cpp) {
221 /* return 0; */
222 return NULL;
223 } else if (fields[6][0] == '\0')
224 spwd.sp_inact = -1;
225
226 /*
227 * Get the number of days after the epoch before the account is
228 * set to expire.
229 */
230
231 if ((spwd.sp_expire = strtol(fields[7], &cpp, 10)) == 0 && *cpp) {
232 /* return 0; */
233 return NULL;
234 } else if (fields[7][0] == '\0')
235 spwd.sp_expire = -1;
236
237 /*
238 * This field is reserved for future use. But it isn't supposed
239 * to have anything other than a valid integer in it.
240 */
241
242 if ((spwd.sp_flag = strtol(fields[8], &cpp, 10)) == 0 && *cpp) {
243 /* return 0; */
244 return NULL;
245 } else if (fields[8][0] == '\0')
246 spwd.sp_flag = -1;
247
248 return (&spwd);
249}
250
251/* fgetspent - get an entry from an /etc/shadow formatted stream */
252struct spwd *fgetspent(FILE *fp)
253{
254 char buf[BUFSIZ];
255 char *cp;
256
257 if (!fp)
258 /* return (0); */
259 return NULL;
260
261 if (fgets(buf, sizeof buf, fp) != (char *) 0) {
262 if ((cp = strchr(buf, '\n')))
263 *cp = '\0';
264 return (sgetspent(buf));
265 }
266 /* return 0; */
267 return NULL;
268}
269
270/*
271 * putspent - put a (struct spwd *) into the (FILE *) you provide.
272 *
273 * this was described in shadow_.h but not implemented, so here
274 * I go. -beppu
275 *
276 */
277int putspent(const struct spwd *sp, FILE *fp)
278{
279 int ret;
280
281 /* seek to end */
282 ret = fseek(fp, 0, SEEK_END);
283 if (ret == -1) {
284 /* return -1; */
285 return 1;
286 }
287
288 /* powered by fprintf */
289 fprintf(fp, "%s:%s:%ld:%ld:%ld:%ld:%ld:%ld:%s\n", sp->sp_namp, /* login name */
290 sp->sp_pwdp, /* encrypted password */
291 sp->sp_lstchg, /* date of last change */
292 sp->sp_min, /* minimum number of days between changes */
293 sp->sp_max, /* maximum number of days between changes */
294 sp->sp_warn, /* number of days of warning before password expires */
295 sp->sp_inact, /* number of days after password expires until
296 the account becomes unusable */
297 sp->sp_expire, /* days since 1/1/70 until account expires */
298 "");
299 return 0;
300}
301
302
diff --git a/loginutils/Makefile b/loginutils/Makefile
new file mode 100644
index 000000000..09b368afc
--- /dev/null
+++ b/loginutils/Makefile
@@ -0,0 +1,30 @@
1# Makefile for busybox
2#
3# Copyright (C) 1999-2002 Erik Andersen <andersee@debian.org>
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 2 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13# General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program; if not, write to the Free Software
17# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18#
19
20TOPDIR:= ../
21LOGINUTILS_DIR:=./
22include $(TOPDIR).config
23include $(TOPDIR)Rules.mak
24include Makefile.in
25all: $(libraries-y)
26-include $(TOPDIR).depend
27
28clean:
29 rm -f *.o *.a $(AR_TARGET)
30
diff --git a/loginutils/Makefile.in b/loginutils/Makefile.in
new file mode 100644
index 000000000..adee35baa
--- /dev/null
+++ b/loginutils/Makefile.in
@@ -0,0 +1,45 @@
1# Makefile for busybox
2#
3# Copyright (C) 1999-2002 Erik Andersen <andersee@debian.org>
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 2 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13# General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program; if not, write to the Free Software
17# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18#
19
20LOGINUTILS_AR:=loginutils.a
21ifndef LOGINUTILS_DIR
22LOGINUTILS_DIR:=$(TOPDIR)loginutils/
23endif
24
25LOGINUTILS-y:=
26LOGINUTILS-$(CONFIG_ADDGROUP) += addgroup.o
27LOGINUTILS-$(CONFIG_ADDUSER) += adduser.o
28LOGINUTILS-$(CONFIG_DELUSER) += deluser.o
29LOGINUTILS-$(CONFIG_GETTY) += getty.o
30LOGINUTILS-$(CONFIG_LOGIN) += login.o tinylogin.o
31LOGINUTILS-$(CONFIG_SU) += su.o tinylogin.o
32
33libraries-y+=$(LOGINUTILS_DIR)$(LOGINUTILS_AR)
34
35needcrypt-y:=
36needcrypt-$(CONFIG_LOGIN) := y
37needcrypt-$(CONFIG_SU) := y
38
39ifeq ($(needcrypt-y),y)
40 libraries-y +=-lcrypt
41endif
42
43$(LOGINUTILS_DIR)$(LOGINUTILS_AR): $(patsubst %,$(LOGINUTILS_DIR)%, $(LOGINUTILS-y))
44 $(AR) -ro $@ $(patsubst %,$(LOGINUTILS_DIR)%, $(LOGINUTILS-y))
45
diff --git a/loginutils/addgroup.c b/loginutils/addgroup.c
new file mode 100644
index 000000000..e04a8d784
--- /dev/null
+++ b/loginutils/addgroup.c
@@ -0,0 +1,168 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * addgroup - add users to /etc/passwd and /etc/shadow
4 *
5 * Copyright (C) 1999 by Lineo, inc. and John Beppu
6 * Copyright (C) 1999,2000,2001 by John Beppu <beppu@codepoet.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24#include <errno.h>
25#include <fcntl.h>
26#include <stdarg.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30#include <sys/param.h>
31#include <sys/stat.h>
32#include <sys/types.h>
33#include <unistd.h>
34#include "busybox.h"
35#include "pwd.h"
36#include "grp.h"
37
38#define GROUP_FILE "/etc/group"
39#define SHADOW_FILE "/etc/gshadow"
40
41
42/* structs __________________________ */
43
44/* data _____________________________ */
45
46/* defaults : should this be in an external file? */
47static const char default_passwd[] = "x";
48
49
50/* make sure gr_name isn't taken, make sure gid is kosher
51 * return 1 on failure */
52static int group_study(const char *filename, struct group *g)
53{
54 FILE *etc_group;
55 gid_t desired;
56
57 struct group *grp;
58 const int max = 65000;
59
60 etc_group = xfopen(filename, "r");
61
62 /* make sure gr_name isn't taken, make sure gid is kosher */
63 desired = g->gr_gid;
64 while ((grp = fgetgrent(etc_group))) {
65 if ((strcmp(grp->gr_name, g->gr_name)) == 0) {
66 error_msg_and_die("%s: group already in use\n", g->gr_name);
67 }
68 if ((desired) && grp->gr_gid == desired) {
69 error_msg_and_die("%d: gid has already been allocated\n",
70 desired);
71 }
72 if ((grp->gr_gid > g->gr_gid) && (grp->gr_gid < max)) {
73 g->gr_gid = grp->gr_gid;
74 }
75 }
76 fclose(etc_group);
77
78 /* gid */
79 if (desired) {
80 g->gr_gid = desired;
81 } else {
82 g->gr_gid++;
83 }
84 /* return 1; */
85 return 0;
86}
87
88/* append a new user to the passwd file */
89static int addgroup(const char *filename, char *group, gid_t gid)
90{
91 FILE *etc_group;
92
93#ifdef CONFIG_FEATURE_SHADOWPASSWDS
94 FILE *etc_gshadow;
95 char *gshadow = SHADOW_FILE;
96#endif
97
98 struct group gr;
99
100 /* group:passwd:gid:userlist */
101 static const char entryfmt[] = "%s:%s:%d:%s\n";
102
103 /* make sure gid and group haven't already been allocated */
104 gr.gr_gid = gid;
105 gr.gr_name = group;
106 if (group_study(filename, &gr))
107 return 1;
108
109 /* add entry to group */
110 etc_group = xfopen(filename, "a");
111
112 fprintf(etc_group, entryfmt, group, default_passwd, gr.gr_gid, "");
113 fclose(etc_group);
114
115
116#ifdef CONFIG_FEATURE_SHADOWPASSWDS
117 /* add entry to gshadow if necessary */
118 if (access(gshadow, F_OK|W_OK) == 0) {
119 etc_gshadow = xfopen(gshadow, "a");
120 fprintf(etc_gshadow, "%s:!::\n", group);
121 fclose(etc_gshadow);
122 }
123#endif
124
125 /* return 1; */
126 return 0;
127}
128
129/*
130 * addgroup will take a login_name as its first parameter.
131 *
132 * gid
133 *
134 * can be customized via command-line parameters.
135 * ________________________________________________________________________ */
136int addgroup_main(int argc, char **argv)
137{
138 int opt;
139 char *group;
140 gid_t gid = 0;
141
142 /* get remaining args */
143 while ((opt = getopt (argc, argv, "g:")) != -1)
144 switch (opt) {
145 case 'g':
146 gid = strtol(optarg, NULL, 10);
147 break;
148 default:
149 show_usage();
150 break;
151 }
152
153 if (optind >= argc) {
154 show_usage();
155 } else {
156 group = argv[optind];
157 }
158
159 if (geteuid() != 0) {
160 error_msg_and_die
161 ("Only root may add a group to the system.");
162 }
163
164 /* werk */
165 return addgroup(GROUP_FILE, group, gid);
166}
167
168/* $Id: addgroup.c,v 1.1 2002/06/04 20:45:05 sandman Exp $ */
diff --git a/loginutils/adduser.c b/loginutils/adduser.c
new file mode 100644
index 000000000..66fcaa23f
--- /dev/null
+++ b/loginutils/adduser.c
@@ -0,0 +1,352 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * adduser - add users to /etc/passwd and /etc/shadow
4 *
5 * Copyright (C) 1999 by Lineo, inc. and John Beppu
6 * Copyright (C) 1999,2000,2001 by John Beppu <beppu@codepoet.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24#include <errno.h>
25#include <fcntl.h>
26#include <stdarg.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30#include <time.h>
31#include <unistd.h>
32#include <sys/param.h>
33#include <sys/stat.h>
34#include <sys/types.h>
35#include "busybox.h"
36#include "pwd.h"
37#include "grp.h"
38
39#define PASSWD_FILE "/etc/passwd"
40#define SHADOW_FILE "/etc/shadow"
41
42
43/* structs __________________________ */
44
45typedef struct {
46 uid_t u;
47 gid_t g;
48} Id;
49
50/* data _____________________________ */
51
52/* defaults : should this be in an external file? */
53static const char default_passwd[] = "x";
54static const char default_gecos[] = "Linux User,,,";
55static const char default_home_prefix[] = "/home";
56static const char default_shell[] = "/bin/sh";
57
58#ifdef CONFIG_FEATURE_SHADOWPASSWDS
59
60#include "shadow.h"
61
62/* shadow in use? */
63static int shadow_enabled = 0;
64#endif
65
66/* remix */
67/* EDR recoded such that the uid may be passed in *p */
68static int passwd_study(const char *filename, struct passwd *p)
69{
70 struct passwd *pw;
71 FILE *passwd;
72
73 const int min = 500;
74 const int max = 65000;
75
76 passwd = wfopen(filename, "r");
77 if (!passwd)
78 return 4;
79
80 /* EDR if uid is out of bounds, set to min */
81 if ((p->pw_uid > max) || (p->pw_uid < min))
82 p->pw_uid = min;
83
84 /* stuff to do:
85 * make sure login isn't taken;
86 * find free uid and gid;
87 */
88 while ((pw = fgetpwent(passwd))) {
89 if (strcmp(pw->pw_name, p->pw_name) == 0) {
90 /* return 0; */
91 return 1;
92 }
93 if ((pw->pw_uid >= p->pw_uid) && (pw->pw_uid < max)
94 && (pw->pw_uid >= min)) {
95 p->pw_uid = pw->pw_uid + 1;
96 }
97 }
98
99 /* EDR check for an already existing gid */
100 while (getgrgid(p->pw_uid) != NULL)
101 p->pw_uid++;
102
103 /* EDR also check for an existing group definition */
104 if (getgrnam(p->pw_name) != NULL)
105 return 3;
106
107 /* EDR bounds check */
108 if ((p->pw_uid > max) || (p->pw_uid < min))
109 return 2;
110
111 /* EDR create new gid always = uid */
112 p->pw_gid = p->pw_uid;
113
114 /* return 1; */
115 return 0;
116}
117
118static void addgroup_wrapper(const char *login, gid_t gid)
119{
120 int argc = 3;
121 const char *argv0_save;
122 char group_id[8];
123 char group_name[32];
124 char *argv[] = { group_name, "-g", group_id };
125
126 argv0_save = applet_name;
127 applet_name = "addgroup";
128 safe_strncpy(group_name, login, 32);
129 sprintf(group_id, "%d", gid);
130 addgroup_main(argc, argv);
131 applet_name = argv0_save;
132}
133
134static void passwd_wrapper(const char *login)
135{
136 static const char prog[] = "passwd";
137 execlp(prog, prog, login, NULL);
138 error_msg_and_die("Failed to execute 'passwd', you must set the password for '%s' manually", login);
139}
140
141#ifdef CONFIG_FEATURE_SHADOWPASSWDS
142/*
143 * pwd_to_spwd - create entries for new spwd structure
144 *
145 * pwd_to_spwd() creates a new (struct spwd) containing the
146 * information in the pointed-to (struct passwd).
147 */
148#define DAY (24L*3600L)
149#define WEEK (7*DAY)
150#define SCALE DAY
151static struct spwd *pwd_to_spwd(const struct passwd *pw)
152{
153 static struct spwd sp;
154
155 /*
156 * Nice, easy parts first. The name and passwd map directly
157 * from the old password structure to the new one.
158 */
159 sp.sp_namp = pw->pw_name;
160 sp.sp_pwdp = pw->pw_passwd;
161
162 /*
163 * Defaults used if there is no pw_age information.
164 */
165 sp.sp_min = 0;
166 sp.sp_max = (10000L * DAY) / SCALE;
167 sp.sp_lstchg = time((time_t *) 0) / SCALE;
168
169 /*
170 * These fields have no corresponding information in the password
171 * file. They are set to uninitialized values.
172 */
173 sp.sp_warn = -1;
174 sp.sp_expire = -1;
175 sp.sp_inact = -1;
176 sp.sp_flag = -1;
177
178 return &sp;
179}
180#endif
181
182/* putpwent(3) remix */
183static int adduser(const char *filename, struct passwd *p)
184{
185 FILE *passwd;
186 int r;
187#ifdef CONFIG_FEATURE_SHADOWPASSWDS
188 FILE *shadow;
189 struct spwd *sp;
190#endif
191
192 /* make sure everything is kosher and setup uid && gid */
193 passwd = wfopen(filename, "a");
194 if (passwd == NULL) {
195 /* return -1; */
196 return 1;
197 }
198 fseek(passwd, 0, SEEK_END);
199
200 /* if (passwd_study(filename, p) == 0) { */
201 r = passwd_study(filename, p);
202 if (r) {
203 if (r == 1)
204 error_msg("%s: login already in use", p->pw_name);
205 else if (r == 2)
206 error_msg("illegal uid or no uids left");
207 else if (r == 3)
208 error_msg("group name %s already in use", p->pw_name);
209 else
210 error_msg("generic error.");
211 /* return -1; */
212 return 1;
213 }
214
215 /* add to passwd */
216 if (putpwent(p, passwd) == -1) {
217 /* return -1; */
218 return 1;
219 }
220 fclose(passwd);
221
222#ifdef CONFIG_FEATURE_SHADOWPASSWDS
223 /* add to shadow if necessary */
224 if (shadow_enabled) {
225 shadow = wfopen(SHADOW_FILE, "a");
226 if (shadow == NULL) {
227 /* return -1; */
228 return 1;
229 }
230 fseek(shadow, 0, SEEK_END);
231 sp = pwd_to_spwd(p);
232 sp->sp_max = 99999; /* debianish */
233 sp->sp_warn = 7;
234 fprintf(shadow, "%s:!:%ld:%ld:%ld:%ld:::\n",
235 sp->sp_namp, sp->sp_lstchg, sp->sp_min, sp->sp_max,
236 sp->sp_warn);
237 fclose(shadow);
238 }
239#endif
240
241 /* add to group */
242 /* addgroup should be responsible for dealing w/ gshadow */
243 addgroup_wrapper(p->pw_name, p->pw_gid);
244
245 /* Clear the umask for this process so it doesn't
246 * * screw up the permissions on the mkdir and chown. */
247 umask(0);
248
249 /* mkdir */
250 if (mkdir(p->pw_dir, 0755)) {
251 perror_msg("%s", p->pw_dir);
252 }
253 /* Set the owner and group so it is owned by the new user. */
254 if (chown(p->pw_dir, p->pw_uid, p->pw_gid)) {
255 perror_msg("%s", p->pw_dir);
256 }
257 /* Now fix up the permissions to 2755. Can't do it before now
258 * since chown will clear the setgid bit */
259 if (chmod(p->pw_dir, 02755)) {
260 perror_msg("%s", p->pw_dir);
261 }
262 /* interactively set passwd */
263 passwd_wrapper(p->pw_name);
264
265 return 0;
266}
267
268
269/* return current uid (root is always uid == 0, right?) */
270static inline uid_t i_am_not_root(void)
271{
272 return geteuid();
273}
274
275/*
276 * adduser will take a login_name as its first parameter.
277 *
278 * home
279 * shell
280 * gecos
281 *
282 * can be customized via command-line parameters.
283 * ________________________________________________________________________ */
284int adduser_main(int argc, char **argv)
285{
286 int i = 0;
287 char opt;
288 const char *login;
289 const char *gecos;
290 const char *home = NULL;
291 const char *shell;
292
293 struct passwd pw;
294
295 /* init */
296 if (argc < 2) {
297 show_usage();
298 }
299 gecos = default_gecos;
300 shell = default_shell;
301
302 /* get args */
303 while ((opt = getopt (argc, argv, "h:g:s:")) != -1)
304 switch (opt) {
305 case 'h':
306 home = argv[++i];
307 break;
308 case 'g':
309 gecos = argv[++i];
310 break;
311 case 's':
312 shell = argv[++i];
313 break;
314 default:
315 show_usage ();
316 break;
317 }
318
319 /* got root? */
320 if (i_am_not_root()) {
321 error_msg_and_die( "Only root may add a user or group to the system.");
322 }
323
324 /* get login */
325 if (optind >= argc) {
326 error_msg_and_die( "no user specified");
327 }
328 login = argv[optind];
329
330 /* create string for $HOME if not specified already */
331 if (!home) {
332 home = concat_path_file(default_home_prefix, login);
333 }
334#ifdef CONFIG_FEATURE_SHADOWPASSWDS
335 /* is /etc/shadow in use? */
336 shadow_enabled = (0 == access(SHADOW_FILE, F_OK));
337#endif
338
339 /* create a passwd struct */
340 pw.pw_name = (char *)login;
341 pw.pw_passwd = (char *)default_passwd;
342 pw.pw_uid = 0;
343 pw.pw_gid = 0;
344 pw.pw_gecos = (char *)gecos;
345 pw.pw_dir = (char *)home;
346 pw.pw_shell = (char *)shell;
347
348 /* grand finale */
349 return adduser(PASSWD_FILE, &pw);
350}
351
352/* $Id: adduser.c,v 1.1 2002/06/04 20:45:05 sandman Exp $ */
diff --git a/loginutils/config.in b/loginutils/config.in
new file mode 100644
index 000000000..265d45ab4
--- /dev/null
+++ b/loginutils/config.in
@@ -0,0 +1,25 @@
1#
2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt.
4#
5
6mainmenu_option next_comment
7comment 'Login/Password Management Utilities'
8
9
10bool 'addgroup' CONFIG_ADDGROUP
11bool 'adduser' CONFIG_ADDUSER
12bool 'deluser' CONFIG_DELUSER
13bool 'delgroup' CONFIG_DELUSER
14bool 'getty' CONFIG_GETTY
15bool 'login' CONFIG_LOGIN
16if [ "$CONFIG_LOGIN" = "y" ]; then
17 bool ' Support for /etc/securetty' CONFIG_FEATURE_SECURETTY
18fi
19bool 'su' CONFIG_SU
20if [ "$CONFIG_ADDUSER" = "y" -o "$CONFIG_DELUSER" = "y" -o "$CONFIG_LOGIN" = "y" -o "$CONFIG_SU" = "y" ]; then
21 bool 'Support for shadow passwords' CONFIG_FEATURE_SHADOWPASSWDS
22fi
23
24endmenu
25
diff --git a/loginutils/deluser.c b/loginutils/deluser.c
new file mode 100644
index 000000000..481a716e7
--- /dev/null
+++ b/loginutils/deluser.c
@@ -0,0 +1,183 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * deluser (remove lusers from the system ;) for TinyLogin
4 *
5 * Copyright (C) 1999 by Lineo, inc. and John Beppu
6 * Copyright (C) 1999,2000,2001 by John Beppu <beppu@codepoet.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24#include <sys/stat.h>
25#include <unistd.h>
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include "busybox.h"
30
31#define PASSWD_FILE "/etc/passwd"
32#define GROUP_FILE "/etc/group"
33#define SHADOW_FILE "/etc/shadow"
34#define GSHADOW_FILE "/etc/gshadow"
35
36
37/* where to start and stop deletion */
38typedef struct {
39 size_t start;
40 size_t stop;
41} Bounds;
42
43/* An interesting side-effect of boundary()'s
44 * implementation is that the first user (typically root)
45 * cannot be removed. Let's call it a feature. */
46static inline Bounds boundary(const char *buffer, const char *login)
47{
48 char needle[256];
49 char *start;
50 char *stop;
51 Bounds b;
52
53 snprintf(needle, 256, "\n%s:", login);
54 needle[255] = 0;
55 start = strstr(buffer, needle);
56 if (!start) {
57 b.start = 0;
58 b.stop = 0;
59 return b;
60 }
61 start++;
62
63 stop = index(start, '\n'); /* index is a BSD-ism */
64 b.start = start - buffer;
65 b.stop = stop - buffer;
66 return b;
67}
68
69/* grep -v ^login (except it only deletes the first match) */
70/* ...in fact, I think I'm going to simplify this later */
71static int del_line_matching(const char *login, const char *filename)
72{
73 char *buffer;
74 FILE *passwd;
75 size_t len;
76 Bounds b;
77 struct stat statbuf;
78
79 /* load into buffer */
80 passwd = fopen(filename, "r");
81 if (!passwd) {
82 return 1;
83 }
84 stat(filename, &statbuf);
85 len = statbuf.st_size;
86 buffer = (char *) malloc(len * sizeof(char));
87
88 if (!buffer) {
89 fclose(passwd);
90 return 1;
91 }
92 fread(buffer, len, sizeof(char), passwd);
93
94 fclose(passwd);
95
96 /* find the user to remove */
97 b = boundary(buffer, login);
98 if (b.stop == 0) {
99 free(buffer);
100 return 1;
101 }
102
103 /* write the file w/o the user */
104 passwd = fopen(filename, "w");
105 if (!passwd) {
106 return 1;
107 }
108 fwrite(buffer, (b.start - 1), sizeof(char), passwd);
109 fwrite(&buffer[b.stop], (len - b.stop), sizeof(char), passwd);
110
111 fclose(passwd);
112
113 return 0;
114}
115
116/* ________________________________________________________________________ */
117int delgroup_main(int argc, char **argv)
118{
119 /* int successful; */
120 int failure;
121
122 if (argc != 2) {
123 show_usage();
124 } else {
125
126 failure = del_line_matching(argv[1], GROUP_FILE);
127#ifdef CONFIG_FEATURE_SHADOWPASSWDS
128 if (access(GSHADOW_FILE, W_OK) == 0) {
129 /* EDR the |= works if the error is not 0, so he had it wrong */
130 failure |= del_line_matching(argv[1], GSHADOW_FILE);
131 }
132#endif /* CONFIG_FEATURE_SHADOWPASSWDS */
133 /* if (!successful) { */
134 if (failure) {
135 error_msg_and_die("%s: Group could not be removed\n", argv[1]);
136 }
137
138 }
139 return (EXIT_SUCCESS);
140}
141
142/* ________________________________________________________________________ */
143int deluser_main(int argc, char **argv)
144{
145 /* int successful; */
146 int failure;
147
148 if (argc != 2) {
149 show_usage();
150 } else {
151
152 failure = del_line_matching(argv[1], PASSWD_FILE);
153 /* if (!successful) { */
154 if (failure) {
155 error_msg_and_die("%s: User could not be removed from %s\n",
156 argv[1], PASSWD_FILE);
157 }
158#ifdef CONFIG_FEATURE_SHADOWPASSWDS
159 failure = del_line_matching(argv[1], SHADOW_FILE);
160 /* if (!successful) { */
161 if (failure) {
162 error_msg_and_die("%s: User could not be removed from %s\n",
163 argv[1], SHADOW_FILE);
164 }
165 failure = del_line_matching(argv[1], GSHADOW_FILE);
166 /* if (!successful) { */
167 if (failure) {
168 error_msg_and_die("%s: User could not be removed from %s\n",
169 argv[1], GSHADOW_FILE);
170 }
171#endif /* CONFIG_FEATURE_SHADOWPASSWDS */
172 failure = del_line_matching(argv[1], GROUP_FILE);
173 /* if (!successful) { */
174 if (failure) {
175 error_msg_and_die("%s: User could not be removed from %s\n",
176 argv[1], GROUP_FILE);
177 }
178
179 }
180 return (EXIT_SUCCESS);
181}
182
183/* $Id: deluser.c,v 1.1 2002/06/04 20:45:05 sandman Exp $ */
diff --git a/loginutils/getty.c b/loginutils/getty.c
new file mode 100644
index 000000000..2144c95ff
--- /dev/null
+++ b/loginutils/getty.c
@@ -0,0 +1,1157 @@
1/* vi: set sw=4 ts=4: */
2/* agetty.c - another getty program for Linux. By W. Z. Venema 1989
3 Ported to Linux by Peter Orbaek <poe@daimi.aau.dk>
4 This program is freely distributable. The entire man-page used to
5 be here. Now read the real man-page agetty.8 instead.
6
7 -f option added by Eric Rasmussen <ear@usfirst.org> - 12/28/95
8
9 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
10 - added Native Language Support
11
12 1999-05-05 Thorsten Kranzkowski <dl8bcu@gmx.net>
13 - enable hardware flow control before displaying /etc/issue
14
15*/
16
17#include <stdio.h>
18#include <stdlib.h>
19#include <unistd.h>
20#include <string.h>
21#include <sys/ioctl.h>
22#include <errno.h>
23#include <sys/stat.h>
24#include <sys/signal.h>
25#include <fcntl.h>
26#include <stdarg.h>
27#include <ctype.h>
28#include <utmp.h>
29#include <getopt.h>
30#include <termios.h>
31#include "busybox.h"
32
33#define _PATH_LOGIN "/bin/login"
34
35#ifdef linux
36#include <sys/param.h>
37#define USE_SYSLOG
38#endif
39
40extern void updwtmp(const char *filename, const struct utmp *ut);
41
42 /* If USE_SYSLOG is undefined all diagnostics go directly to /dev/console. */
43#ifdef USE_SYSLOG
44#include <syslog.h>
45#endif
46
47
48 /*
49 * Some heuristics to find out what environment we are in: if it is not
50 * System V, assume it is SunOS 4.
51 */
52
53#ifdef LOGIN_PROCESS /* defined in System V utmp.h */
54#define SYSV_STYLE /* select System V style getty */
55#endif
56
57 /*
58 * Things you may want to modify.
59 *
60 * If ISSUE is not defined, agetty will never display the contents of the
61 * /etc/issue file. You will not want to spit out large "issue" files at the
62 * wrong baud rate. Relevant for System V only.
63 *
64 * You may disagree with the default line-editing etc. characters defined
65 * below. Note, however, that DEL cannot be used for interrupt generation
66 * and for line editing at the same time.
67 */
68
69#ifdef SYSV_STYLE
70#define ISSUE "/etc/issue" /* displayed before the login prompt */
71#include <sys/utsname.h>
72#include <time.h>
73#endif
74
75#define LOGIN " login: " /* login prompt */
76
77/* Some shorthands for control characters. */
78
79#define CTL(x) (x ^ 0100) /* Assumes ASCII dialect */
80#define CR CTL('M') /* carriage return */
81#define NL CTL('J') /* line feed */
82#define BS CTL('H') /* back space */
83#define DEL CTL('?') /* delete */
84
85/* Defaults for line-editing etc. characters; you may want to change this. */
86
87#define DEF_ERASE DEL /* default erase character */
88#define DEF_INTR CTL('C') /* default interrupt character */
89#define DEF_QUIT CTL('\\') /* default quit char */
90#define DEF_KILL CTL('U') /* default kill char */
91#define DEF_EOF CTL('D') /* default EOF char */
92#define DEF_EOL 0
93#define DEF_SWITCH 0 /* default switch char */
94
95 /*
96 * SunOS 4.1.1 termio is broken. We must use the termios stuff instead,
97 * because the termio -> termios translation does not clear the termios
98 * CIBAUD bits. Therefore, the tty driver would sometimes report that input
99 * baud rate != output baud rate. I did not notice that problem with SunOS
100 * 4.1. We will use termios where available, and termio otherwise.
101 */
102
103/* linux 0.12 termio is broken too, if we use it c_cc[VERASE] isn't set
104 properly, but all is well if we use termios?! */
105
106#ifdef TCGETS
107#undef TCGETA
108#undef TCSETA
109#undef TCSETAW
110#define termio termios
111#define TCGETA TCGETS
112#define TCSETA TCSETS
113#define TCSETAW TCSETSW
114#endif
115
116 /*
117 * This program tries to not use the standard-i/o library. This keeps the
118 * executable small on systems that do not have shared libraries (System V
119 * Release <3).
120 */
121#ifndef BUFSIZ
122#define BUFSIZ 1024
123#endif
124
125 /*
126 * When multiple baud rates are specified on the command line, the first one
127 * we will try is the first one specified.
128 */
129
130#define FIRST_SPEED 0
131
132/* Storage for command-line options. */
133
134#define MAX_SPEED 10 /* max. nr. of baud rates */
135
136struct options {
137 int flags; /* toggle switches, see below */
138 int timeout; /* time-out period */
139 char *login; /* login program */
140 char *tty; /* name of tty */
141 char *initstring; /* modem init string */
142 char *issue; /* alternative issue file */
143 int numspeed; /* number of baud rates to try */
144 int speeds[MAX_SPEED]; /* baud rates to be tried */
145};
146
147#define F_PARSE (1<<0) /* process modem status messages */
148#define F_ISSUE (1<<1) /* display /etc/issue */
149#define F_RTSCTS (1<<2) /* enable RTS/CTS flow control */
150#define F_LOCAL (1<<3) /* force local */
151#define F_INITSTRING (1<<4) /* initstring is set */
152#define F_WAITCRLF (1<<5) /* wait for CR or LF */
153#define F_CUSTISSUE (1<<6) /* give alternative issue file */
154#define F_NOPROMPT (1<<7) /* don't ask for login name! */
155
156/* Storage for things detected while the login name was read. */
157
158struct chardata {
159 int erase; /* erase character */
160 int kill; /* kill character */
161 int eol; /* end-of-line character */
162 int parity; /* what parity did we see */
163 int capslock; /* upper case without lower case */
164};
165
166/* Initial values for the above. */
167
168struct chardata init_chardata = {
169 DEF_ERASE, /* default erase character */
170 DEF_KILL, /* default kill character */
171 13, /* default eol char */
172 0, /* space parity */
173 0, /* no capslock */
174};
175
176struct Speedtab {
177 long speed;
178 int code;
179};
180
181static struct Speedtab speedtab[] = {
182 {50, B50},
183 {75, B75},
184 {110, B110},
185 {134, B134},
186 {150, B150},
187 {200, B200},
188 {300, B300},
189 {600, B600},
190 {1200, B1200},
191 {1800, B1800},
192 {2400, B2400},
193 {4800, B4800},
194 {9600, B9600},
195#ifdef B19200
196 {19200, B19200},
197#endif
198#ifdef B38400
199 {38400, B38400},
200#endif
201#ifdef EXTA
202 {19200, EXTA},
203#endif
204#ifdef EXTB
205 {38400, EXTB},
206#endif
207#ifdef B57600
208 {57600, B57600},
209#endif
210#ifdef B115200
211 {115200, B115200},
212#endif
213#ifdef B230400
214 {230400, B230400},
215#endif
216 {0, 0},
217};
218
219static void parse_args(int argc, char **argv, struct options *op);
220static void parse_speeds(struct options *op, char *arg);
221static void update_utmp(char *line);
222static void open_tty(char *tty, struct termio *tp, int local);
223static void termio_init(struct termio *tp, int speed, struct options *op);
224static void auto_baud(struct termio *tp);
225static void do_prompt(struct options *op, struct termio *tp);
226static void next_speed(struct termio *tp, struct options *op);
227static char *get_logname(struct options *op, struct chardata *cp,
228
229 struct termio *tp);
230static void termio_final(struct options *op, struct termio *tp,
231
232 struct chardata *cp);
233static int caps_lock(const char *s);
234static int bcode(const char *s);
235static void error(const char *fmt, ...);
236
237/* The following is used for understandable diagnostics. */
238
239/* Fake hostname for ut_host specified on command line. */
240static char *fakehost = NULL;
241
242/* ... */
243#ifdef DEBUGGING
244#define debug(s) fprintf(dbf,s); fflush(dbf)
245#define DEBUGTERM "/dev/ttyp0"
246FILE *dbf;
247#else
248#define debug(s) /* nothing */
249#endif
250
251int getty_main(int argc, char **argv)
252{
253 char *logname = NULL; /* login name, given to /bin/login */
254 struct chardata chardata; /* set by get_logname() */
255 struct termio termio; /* terminal mode bits */
256 static struct options options = {
257 F_ISSUE, /* show /etc/issue (SYSV_STYLE) */
258 0, /* no timeout */
259 _PATH_LOGIN, /* default login program */
260 "tty1", /* default tty line */
261 "", /* modem init string */
262 ISSUE, /* default issue file */
263 0, /* no baud rates known yet */
264 };
265
266#ifdef DEBUGGING
267 dbf = xfopen(DEBUGTERM, "w");
268
269 {
270 int i;
271
272 for (i = 1; i < argc; i++) {
273 debug(argv[i]);
274 debug("\n");
275 }
276 }
277#endif
278
279 /* Parse command-line arguments. */
280
281 parse_args(argc, argv, &options);
282
283#ifdef __linux__
284 setsid();
285#endif
286
287 /* Update the utmp file. */
288
289#ifdef SYSV_STYLE
290 update_utmp(options.tty);
291#endif
292
293 debug("calling open_tty\n");
294 /* Open the tty as standard { input, output, error }. */
295 open_tty(options.tty, &termio, options.flags & F_LOCAL);
296
297#ifdef __linux__
298 {
299 int iv;
300
301 iv = getpid();
302 if (ioctl(0, TIOCSPGRP, &iv) < 0)
303 perror_msg("ioctl() TIOCSPGRP call failed");
304 }
305#endif
306 /* Initialize the termio settings (raw mode, eight-bit, blocking i/o). */
307 debug("calling termio_init\n");
308 termio_init(&termio, options.speeds[FIRST_SPEED], &options);
309
310 /* write the modem init string and DON'T flush the buffers */
311 if (options.flags & F_INITSTRING) {
312 debug("writing init string\n");
313 write(1, options.initstring, strlen(options.initstring));
314 }
315
316 if (!(options.flags & F_LOCAL)) {
317 /* go to blocking write mode unless -L is specified */
318 fcntl(1, F_SETFL, fcntl(1, F_GETFL, 0) & ~O_NONBLOCK);
319 }
320
321 /* Optionally detect the baud rate from the modem status message. */
322 debug("before autobaud\n");
323 if (options.flags & F_PARSE)
324 auto_baud(&termio);
325
326 /* Set the optional timer. */
327 if (options.timeout)
328 (void) alarm((unsigned) options.timeout);
329
330 /* optionally wait for CR or LF before writing /etc/issue */
331 if (options.flags & F_WAITCRLF) {
332 char ch;
333
334 debug("waiting for cr-lf\n");
335 while (read(0, &ch, 1) == 1) {
336 ch &= 0x7f; /* strip "parity bit" */
337#ifdef DEBUGGING
338 fprintf(dbf, "read %c\n", ch);
339#endif
340 if (ch == '\n' || ch == '\r')
341 break;
342 }
343 }
344
345 chardata = init_chardata;
346 if (!(options.flags & F_NOPROMPT)) {
347 /* Read the login name. */
348 debug("reading login name\n");
349 /* while ((logname = get_logname(&options, &chardata, &termio)) == 0) */
350 while ((logname = get_logname(&options, &chardata, &termio)) ==
351 NULL) next_speed(&termio, &options);
352 }
353
354 /* Disable timer. */
355
356 if (options.timeout)
357 (void) alarm(0);
358
359 /* Finalize the termio settings. */
360
361 termio_final(&options, &termio, &chardata);
362
363 /* Now the newline character should be properly written. */
364
365 (void) write(1, "\n", 1);
366
367 /* Let the login program take care of password validation. */
368
369 (void) execl(options.login, options.login, "--", logname, (char *) 0);
370 error("%s: can't exec %s: %m", options.tty, options.login);
371 return (0); /* quiet GCC */
372}
373
374/* parse-args - parse command-line arguments */
375
376static void parse_args(int argc, char **argv, struct options *op)
377{
378 extern char *optarg; /* getopt */
379 extern int optind; /* getopt */
380 int c;
381
382 while (isascii(c = getopt(argc, argv, "I:LH:f:hil:mt:wn"))) {
383 switch (c) {
384 case 'I':
385 if (!(op->initstring = strdup(optarg))) {
386 error("can't malloc initstring");
387 break;
388 }
389 {
390 char ch, *p, *q;
391 int i;
392
393 /* copy optarg into op->initstring decoding \ddd
394 octal codes into chars */
395 q = op->initstring;
396 p = optarg;
397 while (*p) {
398 if (*p == '\\') { /* know \\ means \ */
399 p++;
400 if (*p == '\\') {
401 ch = '\\';
402 p++;
403 } else { /* handle \000 - \177 */
404 ch = 0;
405 for (i = 1; i <= 3; i++) {
406 if (*p >= '0' && *p <= '7') {
407 ch <<= 3;
408 ch += *p - '0';
409 p++;
410 } else
411 break;
412 }
413 }
414 *q++ = ch;
415 } else {
416 *q++ = *p++;
417 }
418 }
419 *q = '\0';
420 }
421 op->flags |= F_INITSTRING;
422 break;
423
424 case 'L': /* force local */
425 op->flags |= F_LOCAL;
426 break;
427 case 'H': /* fake login host */
428 fakehost = optarg;
429 break;
430 case 'f': /* custom issue file */
431 op->flags |= F_CUSTISSUE;
432 op->issue = optarg;
433 break;
434 case 'h': /* enable h/w flow control */
435 op->flags |= F_RTSCTS;
436 break;
437 case 'i': /* do not show /etc/issue */
438 op->flags &= ~F_ISSUE;
439 break;
440 case 'l':
441 op->login = optarg; /* non-default login program */
442 break;
443 case 'm': /* parse modem status message */
444 op->flags |= F_PARSE;
445 break;
446 case 'n':
447 op->flags |= F_NOPROMPT;
448 break;
449 case 't': /* time out */
450 if ((op->timeout = atoi(optarg)) <= 0)
451 error("bad timeout value: %s", optarg);
452 break;
453 case 'w':
454 op->flags |= F_WAITCRLF;
455 break;
456 default:
457 show_usage();
458 }
459 }
460 debug("after getopt loop\n");
461 if (argc < optind + 2) /* check parameter count */
462 show_usage();
463
464 /* we loosen up a bit and accept both "baudrate tty" and "tty baudrate" */
465 if ('0' <= argv[optind][0] && argv[optind][0] <= '9') {
466 /* a number first, assume it's a speed (BSD style) */
467 parse_speeds(op, argv[optind++]); /* baud rate(s) */
468 op->tty = argv[optind]; /* tty name */
469 } else {
470 op->tty = argv[optind++]; /* tty name */
471 parse_speeds(op, argv[optind]); /* baud rate(s) */
472 }
473
474 optind++;
475 if (argc > optind && argv[optind])
476 setenv("TERM", argv[optind], 1);
477
478 debug("exiting parseargs\n");
479}
480
481/* parse_speeds - parse alternate baud rates */
482
483static void parse_speeds(struct options *op, char *arg)
484{
485 char *cp;
486
487 debug("entered parse_speeds\n");
488 for (cp = strtok(arg, ","); cp != 0; cp = strtok((char *) 0, ",")) {
489 if ((op->speeds[op->numspeed++] = bcode(cp)) <= 0)
490 error("bad speed: %s", cp);
491 if (op->numspeed > MAX_SPEED)
492 error("too many alternate speeds");
493 }
494 debug("exiting parsespeeds\n");
495}
496
497#ifdef SYSV_STYLE
498
499/* update_utmp - update our utmp entry */
500static void update_utmp(char *line)
501{
502 struct utmp ut;
503 struct utmp *utp;
504 time_t t;
505 int mypid = getpid();
506#if ! (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1))
507 struct flock lock;
508#endif
509
510 /*
511 * The utmp file holds miscellaneous information about things started by
512 * /sbin/init and other system-related events. Our purpose is to update
513 * the utmp entry for the current process, in particular the process type
514 * and the tty line we are listening to. Return successfully only if the
515 * utmp file can be opened for update, and if we are able to find our
516 * entry in the utmp file.
517 */
518 utmpname(_PATH_UTMP);
519 setutent();
520 while ((utp = getutent())
521 && !(utp->ut_type == INIT_PROCESS && utp->ut_pid == mypid)) /* nothing */
522 ;
523
524 if (utp) {
525 memcpy(&ut, utp, sizeof(ut));
526 } else {
527 /* some inits don't initialize utmp... */
528 memset(&ut, 0, sizeof(ut));
529 strncpy(ut.ut_id, line + 3, sizeof(ut.ut_id));
530 }
531 /*endutent(); */
532
533 strncpy(ut.ut_user, "LOGIN", sizeof(ut.ut_user));
534 strncpy(ut.ut_line, line, sizeof(ut.ut_line));
535 if (fakehost)
536 strncpy(ut.ut_host, fakehost, sizeof(ut.ut_host));
537 time(&t);
538 ut.ut_time = t;
539 ut.ut_type = LOGIN_PROCESS;
540 ut.ut_pid = mypid;
541
542 pututline(&ut);
543 endutent();
544
545 {
546 updwtmp(_PATH_WTMP, &ut);
547 }
548}
549
550#endif
551
552/* open_tty - set up tty as standard { input, output, error } */
553static void open_tty(char *tty, struct termio *tp, int local)
554{
555 /* Get rid of the present standard { output, error} if any. */
556
557 (void) close(1);
558 (void) close(2);
559 errno = 0; /* ignore above errors */
560
561 /* Set up new standard input, unless we are given an already opened port. */
562
563 if (strcmp(tty, "-")) {
564 struct stat st;
565
566 /* Sanity checks... */
567
568 if (chdir("/dev"))
569 error("/dev: chdir() failed: %m");
570 if (stat(tty, &st) < 0)
571 error("/dev/%s: %m", tty);
572 if ((st.st_mode & S_IFMT) != S_IFCHR)
573 error("/dev/%s: not a character device", tty);
574
575 /* Open the tty as standard input. */
576
577 (void) close(0);
578 errno = 0; /* ignore close(2) errors */
579
580 debug("open(2)\n");
581 if (open(tty, O_RDWR | O_NONBLOCK, 0) != 0)
582 error("/dev/%s: cannot open as standard input: %m", tty);
583
584 } else {
585
586 /*
587 * Standard input should already be connected to an open port. Make
588 * sure it is open for read/write.
589 */
590
591 if ((fcntl(0, F_GETFL, 0) & O_RDWR) != O_RDWR)
592 error("%s: not open for read/write", tty);
593 }
594
595 /* Set up standard output and standard error file descriptors. */
596 debug("duping\n");
597 if (dup(0) != 1 || dup(0) != 2) /* set up stdout and stderr */
598 error("%s: dup problem: %m", tty); /* we have a problem */
599
600 /*
601 * The following ioctl will fail if stdin is not a tty, but also when
602 * there is noise on the modem control lines. In the latter case, the
603 * common course of action is (1) fix your cables (2) give the modem more
604 * time to properly reset after hanging up. SunOS users can achieve (2)
605 * by patching the SunOS kernel variable "zsadtrlow" to a larger value;
606 * 5 seconds seems to be a good value.
607 */
608
609 if (ioctl(0, TCGETA, tp) < 0)
610 error("%s: ioctl: %m", tty);
611
612 /*
613 * It seems to be a terminal. Set proper protections and ownership. Mode
614 * 0622 is suitable for SYSV <4 because /bin/login does not change
615 * protections. SunOS 4 login will change the protections to 0620 (write
616 * access for group tty) after the login has succeeded.
617 */
618
619#ifdef DEBIAN
620 {
621 /* tty to root.dialout 660 */
622 struct group *gr;
623 int id;
624
625 id = (gr = getgrnam("dialout")) ? gr->gr_gid : 0;
626 chown(tty, 0, id);
627 chmod(tty, 0660);
628
629 /* vcs,vcsa to root.sys 600 */
630 if (!strncmp(tty, "tty", 3) && isdigit(tty[3])) {
631 char *vcs, *vcsa;
632
633 if (!(vcs = strdup(tty)))
634 error("Can't malloc for vcs");
635 if (!(vcsa = malloc(strlen(tty) + 2)))
636 error("Can't malloc for vcsa");
637 strcpy(vcs, "vcs");
638 strcpy(vcs + 3, tty + 3);
639 strcpy(vcsa, "vcsa");
640 strcpy(vcsa + 4, tty + 3);
641
642 id = (gr = getgrnam("sys")) ? gr->gr_gid : 0;
643 chown(vcs, 0, id);
644 chmod(vcs, 0600);
645 chown(vcsa, 0, id);
646 chmod(vcs, 0600);
647
648 free(vcs);
649 free(vcsa);
650 }
651 }
652#else
653 (void) chown(tty, 0, 0); /* root, sys */
654 (void) chmod(tty, 0622); /* crw--w--w- */
655 errno = 0; /* ignore above errors */
656#endif
657}
658
659/* termio_init - initialize termio settings */
660
661static void termio_init(struct termio *tp, int speed, struct options *op)
662{
663
664 /*
665 * Initial termio settings: 8-bit characters, raw-mode, blocking i/o.
666 * Special characters are set after we have read the login name; all
667 * reads will be done in raw mode anyway. Errors will be dealt with
668 * lateron.
669 */
670#ifdef __linux__
671 /* flush input and output queues, important for modems! */
672 (void) ioctl(0, TCFLSH, TCIOFLUSH);
673#endif
674
675 tp->c_cflag = CS8 | HUPCL | CREAD | speed;
676 if (op->flags & F_LOCAL) {
677 tp->c_cflag |= CLOCAL;
678 }
679
680 tp->c_iflag = tp->c_lflag = tp->c_oflag = tp->c_line = 0;
681 tp->c_cc[VMIN] = 1;
682 tp->c_cc[VTIME] = 0;
683
684 /* Optionally enable hardware flow control */
685
686#ifdef CRTSCTS
687 if (op->flags & F_RTSCTS)
688 tp->c_cflag |= CRTSCTS;
689#endif
690
691 (void) ioctl(0, TCSETA, tp);
692
693 /* go to blocking input even in local mode */
694 fcntl(0, F_SETFL, fcntl(0, F_GETFL, 0) & ~O_NONBLOCK);
695
696 debug("term_io 2\n");
697}
698
699/* auto_baud - extract baud rate from modem status message */
700static void auto_baud(struct termio *tp)
701{
702 int speed;
703 int vmin;
704 unsigned iflag;
705 char buf[BUFSIZ];
706 char *bp;
707 int nread;
708
709 /*
710 * This works only if the modem produces its status code AFTER raising
711 * the DCD line, and if the computer is fast enough to set the proper
712 * baud rate before the message has gone by. We expect a message of the
713 * following format:
714 *
715 * <junk><number><junk>
716 *
717 * The number is interpreted as the baud rate of the incoming call. If the
718 * modem does not tell us the baud rate within one second, we will keep
719 * using the current baud rate. It is advisable to enable BREAK
720 * processing (comma-separated list of baud rates) if the processing of
721 * modem status messages is enabled.
722 */
723
724 /*
725 * Use 7-bit characters, don't block if input queue is empty. Errors will
726 * be dealt with lateron.
727 */
728
729 iflag = tp->c_iflag;
730 tp->c_iflag |= ISTRIP; /* enable 8th-bit stripping */
731 vmin = tp->c_cc[VMIN];
732 tp->c_cc[VMIN] = 0; /* don't block if queue empty */
733 (void) ioctl(0, TCSETA, tp);
734
735 /*
736 * Wait for a while, then read everything the modem has said so far and
737 * try to extract the speed of the dial-in call.
738 */
739
740 (void) sleep(1);
741 if ((nread = read(0, buf, sizeof(buf) - 1)) > 0) {
742 buf[nread] = '\0';
743 for (bp = buf; bp < buf + nread; bp++) {
744 if (isascii(*bp) && isdigit(*bp)) {
745 if ((speed = bcode(bp))) {
746 tp->c_cflag &= ~CBAUD;
747 tp->c_cflag |= speed;
748 }
749 break;
750 }
751 }
752 }
753 /* Restore terminal settings. Errors will be dealt with lateron. */
754
755 tp->c_iflag = iflag;
756 tp->c_cc[VMIN] = vmin;
757 (void) ioctl(0, TCSETA, tp);
758}
759
760/* do_prompt - show login prompt, optionally preceded by /etc/issue contents */
761static void do_prompt(struct options *op, struct termio *tp)
762{
763#ifdef ISSUE
764 FILE *fd;
765 int oflag;
766 int c;
767 struct utsname uts;
768
769 (void) uname(&uts);
770#endif
771
772 (void) write(1, "\r\n", 2); /* start a new line */
773#ifdef ISSUE /* optional: show /etc/issue */
774 if ((op->flags & F_ISSUE) && (fd = fopen(op->issue, "r"))) {
775 oflag = tp->c_oflag; /* save current setting */
776 tp->c_oflag |= (ONLCR | OPOST); /* map NL in output to CR-NL */
777 (void) ioctl(0, TCSETAW, tp);
778
779
780 while ((c = getc(fd)) != EOF) {
781 if (c == '\\') {
782 c = getc(fd);
783
784 switch (c) {
785 case 's':
786 (void) printf("%s", uts.sysname);
787 break;
788
789 case 'n':
790 (void) printf("%s", uts.nodename);
791 break;
792
793 case 'r':
794 (void) printf("%s", uts.release);
795 break;
796
797 case 'v':
798 (void) printf("%s", uts.version);
799 break;
800
801 case 'm':
802 (void) printf("%s", uts.machine);
803 break;
804
805 case 'o':
806 {
807 char domainname[256];
808
809 getdomainname(domainname, sizeof(domainname));
810 domainname[sizeof(domainname) - 1] = '\0';
811 printf("%s", domainname);
812 }
813 break;
814
815 case 'd':
816 case 't':
817 {
818 char *weekday[] = { "Sun", "Mon", "Tue", "Wed", "Thu",
819 "Fri", "Sat"
820 };
821 char *month[] = { "Jan", "Feb", "Mar", "Apr", "May",
822 "Jun", "Jul", "Aug", "Sep", "Oct",
823 "Nov", "Dec"
824 };
825 time_t now;
826 struct tm *tm;
827
828 (void) time(&now);
829 tm = localtime(&now);
830
831 if (c == 'd')
832 (void) printf("%s %s %d %d",
833 weekday[tm->tm_wday],
834 month[tm->tm_mon], tm->tm_mday,
835 tm->tm_year <
836 70 ? tm->tm_year +
837 2000 : tm->tm_year + 1900);
838 else
839 (void) printf("%02d:%02d:%02d", tm->tm_hour,
840 tm->tm_min, tm->tm_sec);
841
842 break;
843 }
844
845 case 'l':
846 (void) printf("%s", op->tty);
847 break;
848
849 case 'b':
850 {
851 int i;
852
853 for (i = 0; speedtab[i].speed; i++) {
854 if (speedtab[i].code == (tp->c_cflag & CBAUD)) {
855 printf("%ld", speedtab[i].speed);
856 break;
857 }
858 }
859 break;
860 }
861 case 'u':
862 case 'U':
863 {
864 int users = 0;
865 struct utmp *ut;
866
867 setutent();
868 while ((ut = getutent()))
869 if (ut->ut_type == USER_PROCESS)
870 users++;
871 endutent();
872 printf("%d ", users);
873 if (c == 'U')
874 printf((users == 1) ? "user" : "users");
875 break;
876 }
877 default:
878 (void) putchar(c);
879 }
880 } else
881 (void) putchar(c);
882 }
883 fflush(stdout);
884
885 tp->c_oflag = oflag; /* restore settings */
886 (void) ioctl(0, TCSETAW, tp); /* wait till output is gone */
887 (void) fclose(fd);
888 }
889#endif
890#ifdef __linux__
891 {
892 char hn[MAXHOSTNAMELEN + 1];
893
894 (void) gethostname(hn, MAXHOSTNAMELEN);
895 write(1, hn, strlen(hn));
896 }
897#endif
898 (void) write(1, LOGIN, sizeof(LOGIN) - 1); /* always show login prompt */
899}
900
901/* next_speed - select next baud rate */
902static void next_speed(struct termio *tp, struct options *op)
903{
904 static int baud_index = FIRST_SPEED; /* current speed index */
905
906 baud_index = (baud_index + 1) % op->numspeed;
907 tp->c_cflag &= ~CBAUD;
908 tp->c_cflag |= op->speeds[baud_index];
909 (void) ioctl(0, TCSETA, tp);
910}
911
912/* get_logname - get user name, establish parity, speed, erase, kill, eol */
913/* return NULL on failure, logname on success */
914static char *get_logname(struct options *op, struct chardata *cp, struct termio *tp)
915{
916 static char logname[BUFSIZ];
917 char *bp;
918 char c; /* input character, full eight bits */
919 char ascval; /* low 7 bits of input character */
920 int bits; /* # of "1" bits per character */
921 int mask; /* mask with 1 bit up */
922 static char *erase[] = { /* backspace-space-backspace */
923 "\010\040\010", /* space parity */
924 "\010\040\010", /* odd parity */
925 "\210\240\210", /* even parity */
926 "\210\240\210", /* no parity */
927 };
928
929 /* Initialize kill, erase, parity etc. (also after switching speeds). */
930
931 *cp = init_chardata;
932
933 /* Flush pending input (esp. after parsing or switching the baud rate). */
934
935 (void) sleep(1);
936 (void) ioctl(0, TCFLSH, TCIFLUSH);
937
938 /* Prompt for and read a login name. */
939
940 for (*logname = 0; *logname == 0; /* void */ ) {
941
942 /* Write issue file and prompt, with "parity" bit == 0. */
943
944 do_prompt(op, tp);
945
946 /* Read name, watch for break, parity, erase, kill, end-of-line. */
947
948 for (bp = logname, cp->eol = 0; cp->eol == 0; /* void */ ) {
949
950 /* Do not report trivial EINTR/EIO errors. */
951
952 if (read(0, &c, 1) < 1) {
953 if (errno == EINTR || errno == EIO)
954 exit(0);
955 error("%s: read: %m", op->tty);
956 }
957 /* Do BREAK handling elsewhere. */
958
959 if ((c == 0) && op->numspeed > 1)
960 /* return (0); */
961 return NULL;
962
963 /* Do parity bit handling. */
964
965 if (c != (ascval = (c & 0177))) { /* "parity" bit on ? */
966 for (bits = 1, mask = 1; mask & 0177; mask <<= 1)
967 if (mask & ascval)
968 bits++; /* count "1" bits */
969 cp->parity |= ((bits & 1) ? 1 : 2);
970 }
971 /* Do erase, kill and end-of-line processing. */
972
973 switch (ascval) {
974 case CR:
975 case NL:
976 *bp = 0; /* terminate logname */
977 cp->eol = ascval; /* set end-of-line char */
978 break;
979 case BS:
980 case DEL:
981 case '#':
982 cp->erase = ascval; /* set erase character */
983 if (bp > logname) {
984 (void) write(1, erase[cp->parity], 3);
985 bp--;
986 }
987 break;
988 case CTL('U'):
989 case '@':
990 cp->kill = ascval; /* set kill character */
991 while (bp > logname) {
992 (void) write(1, erase[cp->parity], 3);
993 bp--;
994 }
995 break;
996 case CTL('D'):
997 exit(0);
998 default:
999 if (!isascii(ascval) || !isprint(ascval)) {
1000 /* ignore garbage characters */ ;
1001 } else if (bp - logname >= sizeof(logname) - 1) {
1002 error("%s: input overrun", op->tty);
1003 } else {
1004 (void) write(1, &c, 1); /* echo the character */
1005 *bp++ = ascval; /* and store it */
1006 }
1007 break;
1008 }
1009 }
1010 }
1011 /* Handle names with upper case and no lower case. */
1012
1013 if ((cp->capslock = caps_lock(logname))) {
1014 for (bp = logname; *bp; bp++)
1015 if (isupper(*bp))
1016 *bp = tolower(*bp); /* map name to lower case */
1017 }
1018 return (logname);
1019}
1020
1021/* termio_final - set the final tty mode bits */
1022static void termio_final(struct options *op, struct termio *tp, struct chardata *cp)
1023{
1024 /* General terminal-independent stuff. */
1025
1026 tp->c_iflag |= IXON | IXOFF; /* 2-way flow control */
1027 tp->c_lflag |= ICANON | ISIG | ECHO | ECHOE | ECHOK | ECHOKE;
1028 /* no longer| ECHOCTL | ECHOPRT */
1029 tp->c_oflag |= OPOST;
1030 /* tp->c_cflag = 0; */
1031 tp->c_cc[VINTR] = DEF_INTR; /* default interrupt */
1032 tp->c_cc[VQUIT] = DEF_QUIT; /* default quit */
1033 tp->c_cc[VEOF] = DEF_EOF; /* default EOF character */
1034 tp->c_cc[VEOL] = DEF_EOL;
1035#ifdef __linux__
1036 tp->c_cc[VSWTC] = DEF_SWITCH; /* default switch character */
1037#else
1038 tp->c_cc[VSWTCH] = DEF_SWITCH; /* default switch character */
1039#endif
1040
1041 /* Account for special characters seen in input. */
1042
1043 if (cp->eol == CR) {
1044 tp->c_iflag |= ICRNL; /* map CR in input to NL */
1045 tp->c_oflag |= ONLCR; /* map NL in output to CR-NL */
1046 }
1047 tp->c_cc[VERASE] = cp->erase; /* set erase character */
1048 tp->c_cc[VKILL] = cp->kill; /* set kill character */
1049
1050 /* Account for the presence or absence of parity bits in input. */
1051
1052 switch (cp->parity) {
1053 case 0: /* space (always 0) parity */
1054 break;
1055 case 1: /* odd parity */
1056 tp->c_cflag |= PARODD;
1057 /* FALLTHROUGH */
1058 case 2: /* even parity */
1059 tp->c_cflag |= PARENB;
1060 tp->c_iflag |= INPCK | ISTRIP;
1061 /* FALLTHROUGH */
1062 case (1 | 2): /* no parity bit */
1063 tp->c_cflag &= ~CSIZE;
1064 tp->c_cflag |= CS7;
1065 break;
1066 }
1067 /* Account for upper case without lower case. */
1068
1069 if (cp->capslock) {
1070 tp->c_iflag |= IUCLC;
1071 tp->c_lflag |= XCASE;
1072 tp->c_oflag |= OLCUC;
1073 }
1074 /* Optionally enable hardware flow control */
1075
1076#ifdef CRTSCTS
1077 if (op->flags & F_RTSCTS)
1078 tp->c_cflag |= CRTSCTS;
1079#endif
1080
1081 /* Finally, make the new settings effective */
1082
1083 if (ioctl(0, TCSETA, tp) < 0)
1084 error("%s: ioctl: TCSETA: %m", op->tty);
1085}
1086
1087/* caps_lock - string contains upper case without lower case */
1088/* returns 1 if true, 0 if false */
1089static int caps_lock(const char *s)
1090{
1091 int capslock;
1092
1093 for (capslock = 0; *s; s++) {
1094 if (islower(*s))
1095 return (0);
1096 if (capslock == 0)
1097 capslock = isupper(*s);
1098 }
1099 return (capslock);
1100}
1101
1102/* bcode - convert speed string to speed code; return 0 on failure */
1103static int bcode(const char *s)
1104{
1105 struct Speedtab *sp;
1106 long speed = atol(s);
1107
1108 for (sp = speedtab; sp->speed; sp++)
1109 if (sp->speed == speed)
1110 return (sp->code);
1111 return (0);
1112}
1113
1114/* error - report errors to console or syslog; only understands %s and %m */
1115
1116#define str2cpy(b,s1,s2) strcat(strcpy(b,s1),s2)
1117
1118/*
1119 * output error messages
1120 */
1121static void error(const char *fmt, ...)
1122{
1123 va_list va_alist;
1124 char buf[256], *bp;
1125
1126#ifndef USE_SYSLOG
1127 int fd;
1128#endif
1129
1130#ifdef USE_SYSLOG
1131 buf[0] = '\0';
1132 bp = buf;
1133#else
1134 strncpy(buf, applet_name, 256);
1135 strncat(buf, ": ", 256);
1136 buf[255] = 0;
1137 bp = buf + strlen(buf);
1138#endif
1139
1140 va_start(va_alist, fmt);
1141 vsnprintf(bp, 256 - strlen(buf), fmt, va_alist);
1142 buf[255] = 0;
1143 va_end(va_alist);
1144
1145#ifdef USE_SYSLOG
1146 syslog_msg(LOG_AUTH, LOG_ERR, buf);
1147#else
1148 strncat(bp, "\r\n", 256 - strlen(buf));
1149 buf[255] = 0;
1150 if ((fd = open("/dev/console", 1)) >= 0) {
1151 write(fd, buf, strlen(buf));
1152 close(fd);
1153 }
1154#endif
1155 (void) sleep((unsigned) 10); /* be kind to init(8) */
1156 exit(1);
1157}
diff --git a/loginutils/login.c b/loginutils/login.c
new file mode 100644
index 000000000..4d93ece49
--- /dev/null
+++ b/loginutils/login.c
@@ -0,0 +1,459 @@
1/* vi: set sw=4 ts=4: */
2#include <fcntl.h>
3#include <signal.h>
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
7#include <syslog.h>
8#include <termios.h>
9#include <unistd.h>
10#include <utmp.h>
11#include <sys/resource.h>
12#include <sys/stat.h>
13#include <sys/time.h>
14#include <sys/types.h>
15#include <ctype.h>
16#include <time.h>
17#include "busybox.h"
18
19#include "pwd.h"
20#include "grp.h"
21
22#ifdef CONFIG_FEATURE_SHADOWPASSWDS
23#include "shadow.h"
24#endif
25
26#include "tinylogin.h"
27
28// import from utmp.c
29static void checkutmp(int picky);
30static void setutmp(const char *name, const char *line);
31
32// import from encrypt.c
33extern char *pw_encrypt(const char *clear, const char *salt);
34
35
36// login defines
37#define DEFAULT_USER "UNKNOWN"
38#define DEFAULT_PWD "!"
39#define DEFAULT_SHELL "/bin/sh"
40#define TIMEOUT 60
41#define FAIL_DELAY 3
42#define MOTD_FILE "/etc/motd"
43#define NOLOGIN_FILE "/etc/nologin"
44#define SECURETTY_FILE "/etc/securetty"
45
46/* Stuff global to this file */
47struct utmp utent;
48
49
50static int check_nologin ( int amroot );
51
52#if defined CONFIG_FEATURE_SECURETTY
53static int check_tty ( const char *tty );
54
55#else
56static inline int check_tty ( const char *tty ) { return 1; }
57
58#endif
59
60static int is_my_tty ( const char *tty );
61static const char *login_prompt ( void );
62static void motd ( void );
63static void set_env(int argc, char *const *argv);
64
65
66static void alarm_handler ( int sig )
67{
68 error_msg ( "\nLogin timed out after %d seconds.\n", TIMEOUT );
69 exit ( EXIT_SUCCESS );
70}
71
72
73extern int login_main(int argc, char **argv)
74{
75 char tty[BUFSIZ];
76 char full_tty[200];
77 char fromhost[512];
78 char *tmp;
79 int amroot;
80 int flag;
81 int failed;
82 int count=0;
83 struct passwd *pw, pw_copy;
84
85 int opt_preserve = 0;
86 int opt_fflag = 0;
87 char *opt_host = 0;
88 const char *username = 0;
89 int alarmstarted = 0;
90
91 amroot = ( getuid ( ) == 0 );
92 signal ( SIGALRM, alarm_handler );
93
94 if (( argc > 1 ) && ( TIMEOUT > 0 )) {
95 alarm ( TIMEOUT );
96 alarmstarted = 1;
97 }
98
99 while (( flag = getopt(argc, argv, "f:h:p")) != EOF ) {
100 switch ( flag ) {
101 case 'p':
102 printf ( "PRESERVE\n" );
103 opt_preserve = 1;
104 break;
105 case 'f':
106 /*
107 * username must be a seperate token
108 * (-f root, *NOT* -froot). --marekm
109 */
110 if ( optarg != argv[optind-1] )
111 show_usage ( );
112
113 if ( !amroot ) /* Auth bypass only if real UID is zero */
114 error_msg_and_die ( "login: -f permission denied\n" );
115
116 printf ( "USERNAME: %s\n", optarg );
117
118 username = optarg;
119 opt_fflag = 1;
120 break;
121 case 'h':
122 opt_host = optarg;
123 break;
124 default:
125 show_usage ( );
126 }
127 }
128
129 if ( optind < argc ) // got a username
130 username = argv [optind++];
131
132 if ( !isatty ( 0 ) || !isatty ( 1 ) || !isatty ( 2 ))
133 return EXIT_FAILURE; /* Must be a terminal */
134
135 checkutmp ( !amroot );
136
137 tmp = ttyname ( 0 );
138 if ( tmp && ( strncmp ( tmp, "/dev/", 5 ) == 0 ))
139 safe_strncpy ( tty, tmp + 5, sizeof( tty ));
140 else
141 safe_strncpy ( tty, "UNKNOWN", sizeof( tty ));
142
143 if ( amroot )
144 memset ( utent.ut_host, 0, sizeof utent.ut_host );
145
146 if ( opt_host ) {
147 safe_strncpy ( utent.ut_host, opt_host, sizeof( utent. ut_host ));
148
149 snprintf ( fromhost, sizeof( fromhost ) - 1, " on `%.100s' from `%.200s'", tty, opt_host );
150 }
151 else
152 snprintf ( fromhost, sizeof( fromhost ) - 1, " on `%.100s'", tty );
153
154 openlog ( "login", LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_AUTH );
155
156 while ( 1 ) {
157 failed = 0;
158
159 if ( !username || !username[0] )
160 username = login_prompt ( );
161
162 if ( !alarmstarted && ( TIMEOUT > 0 )) {
163 alarm ( TIMEOUT );
164 alarmstarted = 1;
165 }
166
167 if (!( pw = getpwnam ( username ))) {
168 pw_copy. pw_name = DEFAULT_USER;
169 pw_copy. pw_passwd = DEFAULT_PWD;
170 pw_copy. pw_shell = DEFAULT_SHELL;
171 opt_fflag = 0;
172 failed = 1;
173 } else
174 pw_copy = *pw;
175
176 pw = &pw_copy;
177
178 if (( pw-> pw_passwd [0] == '!' ) || ( pw-> pw_passwd[0] == '*' ))
179 failed = 1;
180
181 if ( opt_fflag ) {
182 opt_fflag = 0;
183 goto auth_ok;
184 }
185
186 if (( pw-> pw_uid == 0 ) && ( !check_tty ( tty )))
187 failed = 1;
188
189 /* Don't check the password if password entry is empty (!) */
190 if ( !pw-> pw_passwd[0] )
191 goto auth_ok;
192
193 /* authorization takes place here */
194 if ( correct_password ( pw ))
195 goto auth_ok;
196
197 syslog ( LOG_WARNING, "invalid password for `%s'%s\n", pw-> pw_name, fromhost);
198 failed = 1;
199
200auth_ok:
201 if ( !failed)
202 break;
203
204 { // delay next try
205 time_t start, now;
206
207 time ( &start );
208 now = start;
209 while ( difftime ( now, start ) < FAIL_DELAY) {
210 sleep ( FAIL_DELAY );
211 time ( &now );
212 }
213 }
214
215 puts("Login incorrect");
216 if ( ++count == 3 )
217 return EXIT_FAILURE;
218 }
219
220 alarm ( 0 );
221 if ( check_nologin ( pw-> pw_uid == 0 ))
222 return EXIT_FAILURE;
223
224 setutmp ( username, tty );
225 if ( *tty != '/' )
226 snprintf ( full_tty, sizeof( full_tty ) - 1, "/dev/%s", tty);
227 else
228 safe_strncpy ( full_tty, tty, sizeof( full_tty ) - 1 );
229
230 if ( !is_my_tty ( full_tty ))
231 syslog ( LOG_ERR, "unable to determine TTY name, got %s\n", full_tty );
232
233 /* Try these, but don't complain if they fail
234 * (for example when the root fs is read only) */
235 chown ( full_tty, pw-> pw_uid, pw-> pw_gid );
236 chmod ( full_tty, 0600 );
237
238 change_identity ( pw );
239 setup_environment ( pw-> pw_shell, 1, !opt_preserve, pw );
240
241 motd ( );
242 signal ( SIGALRM, SIG_DFL ); /* default alarm signal */
243
244 if ( pw-> pw_uid == 0 )
245 syslog ( LOG_INFO, "root login %s\n", fromhost );
246
247 run_shell ( pw-> pw_shell, 1, 0, 0 ); /* exec the shell finally. */
248
249 return EXIT_FAILURE;
250}
251
252
253
254static const char *login_prompt ( void )
255{
256 char buf [1024];
257 char *sp, *ep;
258
259 gethostname ( buf, sizeof( buf ));
260 printf ( "\nBusyBox on %s login: ", buf );
261 fflush ( stdout );
262
263 if ( !fgets ( buf, sizeof( buf ) - 1, stdin ))
264 return 0;
265
266 if ( !strchr ( buf, '\n' ));
267 return 0;
268
269 for ( sp = buf; isspace ( *sp ); sp++ ) { }
270 for ( ep = sp; isgraph ( *ep ); ep++ ) { }
271
272 *ep = 0;
273 return sp;
274}
275
276
277static int check_nologin ( int amroot )
278{
279 if ( access ( NOLOGIN_FILE, F_OK ) == 0 ) {
280 FILE *fp;
281 int c;
282
283 if (( fp = fopen ( NOLOGIN_FILE, "r" ))) {
284 while (( c = getc ( fp )) != EOF )
285 putchar (( c == '\n' ) ? '\r' : c );
286
287 fflush ( stdout );
288 fclose ( fp );
289 } else {
290 puts ( "\r\nSystem closed for routine maintenance.\r" );
291 }
292 if ( !amroot )
293 return 1;
294
295 puts ( "\r\n[Disconnect bypassed -- root login allowed.]\r" );
296 }
297 return 0;
298}
299
300#ifdef CONFIG_FEATURE_SECURETTY
301
302static int check_tty ( const char *tty )
303{
304 FILE *fp;
305 int i;
306 char buf[BUFSIZ];
307
308 if (( fp = fopen ( SECURETTY_FILE, "r" ))) {
309 while ( fgets ( buf, sizeof( buf ) - 1, fp )) {
310 for ( i = xstrlen( buf ) - 1; i >= 0; --i ) {
311 if ( !isspace ( buf[i] ))
312 break;
313 }
314 buf[++i] = '\0';
315 if (( buf [0] == '\0' ) || ( buf [0] == '#' ))
316 continue;
317
318 if ( strcmp ( buf, tty ) == 0 ) {
319 fclose ( fp );
320 return 1;
321 }
322 }
323 fclose(fp);
324 return 0;
325 }
326 else {
327 syslog ( LOG_WARNING, "cannot open securetty file.\n" );
328 return 1;
329 }
330}
331
332#endif
333
334/* returns 1 if true */
335static int is_my_tty ( const char *tty )
336{
337 struct stat by_name, by_fd;
338
339 if ( stat ( tty, &by_name ) || fstat ( 0, &by_fd ))
340 return 0;
341
342 if ( by_name. st_rdev != by_fd. st_rdev )
343 return 0;
344 else
345 return 1;
346}
347
348
349static void motd ( )
350{
351 FILE *fp;
352 register int c;
353
354 if (( fp = fopen ( MOTD_FILE, "r" ))) {
355 while (( c = getc ( fp )) != EOF )
356 putchar ( c );
357 fclose ( fp );
358 }
359}
360
361
362// vv Taken from tinylogin utmp.c vv
363
364#define _WTMP_FILE "/var/log/wtmp"
365
366#define NO_UTENT \
367 "No utmp entry. You must exec \"login\" from the lowest level \"sh\""
368#define NO_TTY \
369 "Unable to determine your tty name."
370
371/*
372 * checkutmp - see if utmp file is correct for this process
373 *
374 * System V is very picky about the contents of the utmp file
375 * and requires that a slot for the current process exist.
376 * The utmp file is scanned for an entry with the same process
377 * ID. If no entry exists the process exits with a message.
378 *
379 * The "picky" flag is for network and other logins that may
380 * use special flags. It allows the pid checks to be overridden.
381 * This means that getty should never invoke login with any
382 * command line flags.
383 */
384
385static void checkutmp(int picky)
386{
387 char *line;
388 struct utmp *ut;
389 pid_t pid = getpid();
390
391 setutent();
392
393 /* First, try to find a valid utmp entry for this process. */
394 while ((ut = getutent()))
395 if (ut->ut_pid == pid && ut->ut_line[0] && ut->ut_id[0] &&
396 (ut->ut_type == LOGIN_PROCESS || ut->ut_type == USER_PROCESS))
397 break;
398
399 /* If there is one, just use it, otherwise create a new one. */
400 if (ut) {
401 utent = *ut;
402 } else {
403 if (picky) {
404 puts(NO_UTENT);
405 exit(1);
406 }
407 line = ttyname(0);
408 if (!line) {
409 puts(NO_TTY);
410 exit(1);
411 }
412 if (strncmp(line, "/dev/", 5) == 0)
413 line += 5;
414 memset((void *) &utent, 0, sizeof utent);
415 utent.ut_type = LOGIN_PROCESS;
416 utent.ut_pid = pid;
417 strncpy(utent.ut_line, line, sizeof utent.ut_line);
418 /* XXX - assumes /dev/tty?? */
419 strncpy(utent.ut_id, utent.ut_line + 3, sizeof utent.ut_id);
420 strncpy(utent.ut_user, "LOGIN", sizeof utent.ut_user);
421 time(&utent.ut_time);
422 }
423}
424
425#if __GNU_LIBRARY__ < 5
426/*
427 * Some systems already have updwtmp() and possibly updwtmpx(). Others
428 * don't, so we re-implement these functions if necessary. --marekm
429 */
430static void updwtmp(const char *filename, const struct utmp *ut)
431{
432 int fd;
433
434 fd = open(filename, O_APPEND | O_WRONLY, 0);
435 if (fd >= 0) {
436 write(fd, (const char *) ut, sizeof(*ut));
437 close(fd);
438 }
439}
440#endif
441
442/*
443 * setutmp - put a USER_PROCESS entry in the utmp file
444 *
445 * setutmp changes the type of the current utmp entry to
446 * USER_PROCESS. the wtmp file will be updated as well.
447 */
448
449static void setutmp(const char *name, const char *line)
450{
451 utent.ut_type = USER_PROCESS;
452 strncpy(utent.ut_user, name, sizeof utent.ut_user);
453 time(&utent.ut_time);
454 /* other fields already filled in by checkutmp above */
455 setutent();
456 pututline(&utent);
457 endutent();
458 updwtmp(_WTMP_FILE, &utent);
459}
diff --git a/loginutils/su.c b/loginutils/su.c
new file mode 100644
index 000000000..33e62e837
--- /dev/null
+++ b/loginutils/su.c
@@ -0,0 +1,167 @@
1/* vi: set sw=4 ts=4: */
2
3#include "busybox.h"
4
5#include <fcntl.h>
6#include <signal.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10#include <syslog.h>
11#include <termios.h>
12#include <unistd.h>
13#include <utmp.h>
14#include <sys/resource.h>
15#include <sys/stat.h>
16#include <sys/time.h>
17#include <sys/types.h>
18#include <ctype.h>
19#include <time.h>
20
21#include "pwd.h"
22#include "grp.h"
23
24#include "tinylogin.h"
25
26
27
28/* The shell to run if none is given in the user's passwd entry. */
29#define DEFAULT_SHELL "/bin/sh"
30#define DEFAULT_USER "root"
31
32//#define SYSLOG_SUCCESS
33#define SYSLOG_FAILURE
34
35
36#if defined( SYSLOG_SUCCESS ) || defined( SYSLOG_FAILURE )
37/* Log the fact that someone has run su to the user given by PW;
38 if SUCCESSFUL is nonzero, they gave the correct password, etc. */
39
40static void log_su ( const struct passwd *pw, int successful )
41{
42 const char *old_user, *tty;
43
44#if !defined( SYSLOG_SUCESS )
45 if ( successful )
46 return;
47#endif
48#if !defined( SYSLOG_FAILURE )
49 if ( !successful )
50 return;
51#endif
52
53 if ( pw-> pw_uid ) // not to root -> ignored
54 return;
55
56 /* The utmp entry (via getlogin) is probably the best way to identify
57 the user, especially if someone su's from a su-shell. */
58 old_user = getlogin ( );
59 if ( !old_user ) {
60 /* getlogin can fail -- usually due to lack of utmp entry. Resort to getpwuid. */
61 struct passwd *pwd = getpwuid ( getuid ( ));
62 old_user = ( pwd ? pwd-> pw_name : "" );
63 }
64
65 tty = ttyname ( 2 );
66
67 openlog ( "su", 0, LOG_AUTH );
68 syslog ( LOG_NOTICE, "%s%s on %s", successful ? "" : "FAILED SU ", old_user, tty ? tty : "none" );
69}
70#endif
71
72
73
74int su_main ( int argc, char **argv )
75{
76 int flag;
77 int opt_preserve = 0;
78 int opt_loginshell = 0;
79 char *opt_shell = 0;
80 char *opt_command = 0;
81 char *opt_username = DEFAULT_USER;
82 char **opt_args = 0;
83 struct passwd *pw, pw_copy;
84
85
86 while (( flag = getopt ( argc, argv, "c:lmps:" )) != -1 ) {
87 switch ( flag ) {
88 case 'c':
89 opt_command = optarg;
90 break;
91 case 'm':
92 case 'p':
93 opt_preserve = 1;
94 break;
95 case 's':
96 opt_shell = optarg;
97 break;
98 case 'l':
99 opt_loginshell = 1;
100 break;
101 default:
102 show_usage ( );
103 break;
104 }
105 }
106
107 if (( optind < argc ) && ( argv [optind][0] == '-' ) && ( argv [optind][1] == 0 )) {
108 opt_loginshell = 1;
109 ++optind;
110 }
111
112 /* get user if specified */
113 if ( optind < argc )
114 opt_username = argv [optind++];
115
116 if ( optind < argc )
117 opt_args = argv + optind;
118
119
120 pw = getpwnam ( opt_username );
121 if ( !pw )
122 error_msg_and_die ( "user %s does not exist", opt_username );
123
124 /* Make sure pw->pw_shell is non-NULL. It may be NULL when NEW_USER
125 is a username that is retrieved via NIS (YP), but that doesn't have
126 a default shell listed. */
127 if ( !pw-> pw_shell || !pw->pw_shell [0] )
128 pw-> pw_shell = (char *) DEFAULT_SHELL;
129
130 /* Make a copy of the password information and point pw at the local
131 copy instead. Otherwise, some systems (e.g. Linux) would clobber
132 the static data through the getlogin call from log_su. */
133 pw_copy = *pw;
134 pw = &pw_copy;
135 pw-> pw_name = xstrdup ( pw-> pw_name );
136 pw-> pw_dir = xstrdup ( pw-> pw_dir );
137 pw-> pw_shell = xstrdup ( pw-> pw_shell );
138
139 if (( getuid ( ) == 0 ) || correct_password ( pw ))
140 log_su ( pw, 1 );
141 else {
142 log_su ( pw, 0 );
143 error_msg_and_die ( "incorrect password" );
144 }
145
146 if ( !opt_shell && opt_preserve )
147 opt_shell = getenv ( "SHELL" );
148
149 if ( opt_shell && getuid ( ) && restricted_shell ( pw-> pw_shell ))
150 {
151 /* The user being su'd to has a nonstandard shell, and so is
152 probably a uucp account or has restricted access. Don't
153 compromise the account by allowing access with a standard
154 shell. */
155 fputs ( "using restricted shell\n", stderr );
156 opt_shell = 0;
157 }
158
159 if ( !opt_shell )
160 opt_shell = xstrdup ( pw-> pw_shell );
161
162 change_identity ( pw );
163 setup_environment ( opt_shell, opt_loginshell, !opt_preserve, pw );
164 run_shell ( opt_shell, opt_loginshell, opt_command, opt_args );
165
166 return EXIT_FAILURE;
167}
diff --git a/loginutils/tinylogin.c b/loginutils/tinylogin.c
new file mode 100644
index 000000000..bd611fd70
--- /dev/null
+++ b/loginutils/tinylogin.c
@@ -0,0 +1,209 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Copyright 1989 - 1991, Julianne Frances Haugh <jockgrrl@austin.rr.com>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31#include "busybox.h"
32
33#include <stdio.h>
34#include <errno.h>
35#include <unistd.h>
36#include <string.h>
37#include <stdlib.h>
38#include <syslog.h>
39#include <ctype.h>
40
41#include "pwd.h"
42#include "grp.h"
43
44#ifdef CONFIG_FEATURE_SHADOWPASSWDS
45#include "shadow.h"
46#endif
47
48#define DEFAULT_LOGIN_PATH "/bin:/usr/bin"
49#define DEFAULT_ROOT_LOGIN_PATH "/usr/sbin:/bin:/usr/bin:/sbin"
50
51
52static void xsetenv ( const char *key, const char *value )
53{
54 if ( setenv ( key, value, 1 ))
55 error_msg_and_die ( "out of memory" );
56}
57
58/* Become the user and group(s) specified by PW. */
59
60void change_identity ( const struct passwd *pw )
61{
62 if ( initgroups ( pw-> pw_name, pw-> pw_gid ) == -1 )
63 perror_msg_and_die ( "cannot set groups" );
64 endgrent ( );
65
66 if ( setgid ( pw-> pw_gid ))
67 perror_msg_and_die ( "cannot set group id" );
68 if ( setuid ( pw->pw_uid ))
69 perror_msg_and_die ( "cannot set user id" );
70}
71
72/* Run SHELL, or DEFAULT_SHELL if SHELL is empty.
73 If COMMAND is nonzero, pass it to the shell with the -c option.
74 If ADDITIONAL_ARGS is nonzero, pass it to the shell as more
75 arguments. */
76
77void run_shell ( const char *shell, int loginshell, const char *command, const char **additional_args )
78{
79 const char **args;
80 int argno = 1;
81 int additional_args_cnt = 0;
82
83 for ( args = additional_args; args && *args; args++ )
84 additional_args_cnt++;
85
86 if ( additional_args )
87 args = (const char **) xmalloc (sizeof (char *) * ( 4 + additional_args_cnt ));
88 else
89 args = (const char **) xmalloc (sizeof (char *) * 4 );
90
91 args [0] = get_last_path_component ( xstrdup ( shell ));
92
93 if ( loginshell ) {
94 char *args0 = xmalloc ( xstrlen ( args [0] ) + 2 );
95 args0 [0] = '-';
96 strcpy ( args0 + 1, args [0] );
97 args [0] = args0;
98 }
99
100 if ( command ) {
101 args [argno++] = "-c";
102 args [argno++] = command;
103 }
104 if ( additional_args ) {
105 for ( ; *additional_args; ++additional_args )
106 args [argno++] = *additional_args;
107 }
108 args [argno] = 0;
109 execv ( shell, (char **) args );
110 perror_msg_and_die ( "cannot run %s", shell );
111}
112
113/* Return 1 if SHELL is a restricted shell (one not returned by
114 getusershell), else 0, meaning it is a standard shell. */
115
116int restricted_shell ( const char *shell )
117{
118 char *line;
119
120 setusershell ( );
121 while (( line = getusershell ( ))) {
122 if (( *line != '#' ) && ( strcmp ( line, shell ) == 0 ))
123 break;
124 }
125 endusershell ( );
126 return line ? 0 : 1;
127}
128
129/* Update `environ' for the new shell based on PW, with SHELL being
130 the value for the SHELL environment variable. */
131
132void setup_environment ( const char *shell, int loginshell, int changeenv, const struct passwd *pw )
133{
134 if ( loginshell ) {
135 char *term;
136
137 /* Change the current working directory to be the home directory
138 * of the user. It is a fatal error for this process to be unable
139 * to change to that directory. There is no "default" home
140 * directory.
141 * Some systems default to HOME=/
142 */
143 if ( chdir ( pw-> pw_dir )) {
144 if ( chdir ( "/" )) {
145 syslog ( LOG_WARNING, "unable to cd to %s' for user %s'\n", pw-> pw_dir, pw-> pw_name );
146 error_msg_and_die ( "cannot cd to home directory or /" );
147 }
148 fputs ( "warning: cannot change to home directory\n", stderr );
149 }
150
151 /* Leave TERM unchanged. Set HOME, SHELL, USER, LOGNAME, PATH.
152 Unset all other environment variables. */
153 term = getenv ("TERM");
154 clearenv ( );
155 if ( term )
156 xsetenv ( "TERM", term );
157 xsetenv ( "HOME", pw-> pw_dir );
158 xsetenv ( "SHELL", shell );
159 xsetenv ( "USER", pw-> pw_name );
160 xsetenv ( "LOGNAME", pw-> pw_name );
161 xsetenv ( "PATH", ( pw-> pw_uid ? DEFAULT_LOGIN_PATH : DEFAULT_ROOT_LOGIN_PATH ));
162 }
163 else if ( changeenv ) {
164 /* Set HOME, SHELL, and if not becoming a super-user,
165 USER and LOGNAME. */
166 xsetenv ( "HOME", pw-> pw_dir );
167 xsetenv ( "SHELL", shell );
168 if ( pw-> pw_uid ) {
169 xsetenv ( "USER", pw-> pw_name );
170 xsetenv ( "LOGNAME", pw-> pw_name );
171 }
172 }
173}
174
175/* Ask the user for a password.
176 Return 1 if the user gives the correct password for entry PW,
177 0 if not. Return 1 without asking for a password if run by UID 0
178 or if PW has an empty password. */
179
180int correct_password ( const struct passwd *pw )
181{
182 char *unencrypted, *encrypted, *correct;
183
184#ifdef CONFIG_FEATURE_SHADOWPASSWDS
185 if (( strcmp ( pw-> pw_passwd, "x" ) == 0 ) || ( strcmp ( pw-> pw_passwd, "*" ) == 0 )) {
186 struct spwd *sp = getspnam ( pw-> pw_name );
187
188 if ( !sp )
189 error_msg_and_die ( "no valid shadow password" );
190
191 correct = sp-> sp_pwdp;
192 }
193 else
194#endif
195 correct = pw-> pw_passwd;
196
197 if ( correct == 0 || correct[0] == '\0' )
198 return 1;
199
200 unencrypted = getpass ( "Password: " );
201 if ( !unencrypted )
202 {
203 fputs ( "getpass: cannot open /dev/tty\n", stderr );
204 return 0;
205 }
206 encrypted = crypt ( unencrypted, correct );
207 memset ( unencrypted, 0, xstrlen ( unencrypted ));
208 return ( strcmp ( encrypted, correct ) == 0 ) ? 1 : 0;
209}
diff --git a/loginutils/tinylogin.h b/loginutils/tinylogin.h
new file mode 100644
index 000000000..5e56a2c7f
--- /dev/null
+++ b/loginutils/tinylogin.h
@@ -0,0 +1,10 @@
1#ifndef BB_LOGINUTILS_SHELL_H
2#define BB_LOGINUTILS_SHELL_H
3
4extern void change_identity ( const struct passwd *pw );
5extern void run_shell ( const char *shell, int loginshell, const char *command, char **additional_args );
6extern int restricted_shell ( const char *shell );
7extern void setup_environment ( const char *shell, int loginshell, int changeenv, const struct passwd *pw );
8extern int correct_password ( const struct passwd *pw );
9
10#endif