diff options
author | sandman <sandman@69ca8d6d-28ef-0310-b511-8ec308f3f277> | 2002-06-04 20:45:46 +0000 |
---|---|---|
committer | sandman <sandman@69ca8d6d-28ef-0310-b511-8ec308f3f277> | 2002-06-04 20:45:46 +0000 |
commit | a96f0888d30f5eb1cac685d2bee61cca8767209c (patch) | |
tree | bd211c50ca4a34fd4c6317696c62564fb77171e9 | |
parent | 833593c5b14bd14e14180776f15a8368f1a5f5dd (diff) | |
download | busybox-w32-a96f0888d30f5eb1cac685d2bee61cca8767209c.tar.gz busybox-w32-a96f0888d30f5eb1cac685d2bee61cca8767209c.tar.bz2 busybox-w32-a96f0888d30f5eb1cac685d2bee61cca8767209c.zip |
Bigger patch for (partial) tinylogin integration
- Made a new dir loginutils
- Moved all applets from pwd_grp to loginutils
- Added new applets su.c login.c to loginutils
- Made a new dir libpwdgrp
- Moved everything from pwd_grp/libpwd_grp there
- Added shadow.c to libpwdgrp
- Removed dir pwd_grp
- Added usage strings for login and su to usage.h
- Changed main Makefile to reflect the dir rearrangements
[Parts of this patch may overlap with my other two patches]
git-svn-id: svn://busybox.net/trunk/busybox@4857 69ca8d6d-28ef-0310-b511-8ec308f3f277
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | include/usage.h | 16 | ||||
-rw-r--r-- | libpwdgrp/Makefile | 30 | ||||
-rw-r--r-- | libpwdgrp/Makefile.in | 35 | ||||
-rw-r--r-- | libpwdgrp/__getgrent.c | 204 | ||||
-rw-r--r-- | libpwdgrp/__getpwent.c | 115 | ||||
-rw-r--r-- | libpwdgrp/fgetgrent.c | 35 | ||||
-rw-r--r-- | libpwdgrp/fgetpwent.c | 35 | ||||
-rw-r--r-- | libpwdgrp/getgrgid.c | 44 | ||||
-rw-r--r-- | libpwdgrp/getgrnam.c | 50 | ||||
-rw-r--r-- | libpwdgrp/getpw.c | 47 | ||||
-rw-r--r-- | libpwdgrp/getpwnam.c | 51 | ||||
-rw-r--r-- | libpwdgrp/getpwuid.c | 44 | ||||
-rw-r--r-- | libpwdgrp/grent.c | 54 | ||||
-rw-r--r-- | libpwdgrp/initgroups.c | 115 | ||||
-rw-r--r-- | libpwdgrp/putpwent.c | 39 | ||||
-rw-r--r-- | libpwdgrp/pwent.c | 58 | ||||
-rw-r--r-- | libpwdgrp/setgroups.c | 42 | ||||
-rw-r--r-- | libpwdgrp/shadow.c | 302 | ||||
-rw-r--r-- | loginutils/Makefile | 30 | ||||
-rw-r--r-- | loginutils/Makefile.in | 45 | ||||
-rw-r--r-- | loginutils/addgroup.c | 168 | ||||
-rw-r--r-- | loginutils/adduser.c | 352 | ||||
-rw-r--r-- | loginutils/config.in | 25 | ||||
-rw-r--r-- | loginutils/deluser.c | 183 | ||||
-rw-r--r-- | loginutils/getty.c | 1157 | ||||
-rw-r--r-- | loginutils/login.c | 459 | ||||
-rw-r--r-- | loginutils/su.c | 167 | ||||
-rw-r--r-- | loginutils/tinylogin.c | 209 | ||||
-rw-r--r-- | loginutils/tinylogin.h | 10 |
30 files changed, 4123 insertions, 2 deletions
@@ -22,8 +22,8 @@ include $(TOPDIR).config | |||
22 | include $(TOPDIR)Rules.mak | 22 | include $(TOPDIR)Rules.mak |
23 | SUBDIRS:=applets archival archival/libunarchive console-tools \ | 23 | SUBDIRS:=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 | ||
28 | all: do-it-all | 28 | all: 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 | |||
20 | TOPDIR:= ../ | ||
21 | LIBPWDGRP_DIR:=./ | ||
22 | include $(TOPDIR).config | ||
23 | include $(TOPDIR)Rules.mak | ||
24 | include Makefile.in | ||
25 | all: $(libraries-y) | ||
26 | -include $(TOPDIR).depend | ||
27 | |||
28 | clean: | ||
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 | |||
20 | LIBPWDGRP_AR:=libpwdgrp.a | ||
21 | ifndef $(LIBPWDGRP_DIR) | ||
22 | LIBPWDGRP_DIR:=$(TOPDIR)libpwdgrp/ | ||
23 | endif | ||
24 | |||
25 | LIBPWDGRP-y:= | ||
26 | LIBPWDGRP-$(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 | ||
29 | LIBPWDGRP-$(CONFIG_USE_BB_SHADOW) += shadow.o | ||
30 | |||
31 | libraries-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 | */ | ||
74 | struct 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 | |||
37 | struct 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 | |||
27 | struct 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 | |||
27 | struct 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 | |||
28 | struct 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 | |||
29 | struct 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 | |||
28 | int 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 | |||
30 | struct 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 | |||
28 | struct 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 | |||
33 | static int grp_fd = -1; | ||
34 | |||
35 | void setgrent(void) | ||
36 | { | ||
37 | if (grp_fd != -1) | ||
38 | close(grp_fd); | ||
39 | grp_fd = open("/etc/group", O_RDONLY); | ||
40 | } | ||
41 | |||
42 | void endgrent(void) | ||
43 | { | ||
44 | if (grp_fd != -1) | ||
45 | close(grp_fd); | ||
46 | grp_fd = -1; | ||
47 | } | ||
48 | |||
49 | struct 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 | |||
68 | int 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 | |||
27 | int 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 */ | ||
36 | static int pw_fd = -1; | ||
37 | |||
38 | void setpwent(void) | ||
39 | { | ||
40 | if (pw_fd != -1) | ||
41 | close(pw_fd); | ||
42 | |||
43 | pw_fd = open("/etc/passwd", O_RDONLY); | ||
44 | } | ||
45 | |||
46 | void endpwent(void) | ||
47 | { | ||
48 | if (pw_fd != -1) | ||
49 | close(pw_fd); | ||
50 | pw_fd = -1; | ||
51 | } | ||
52 | |||
53 | struct 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 | |||
45 | static FILE *shadow; | ||
46 | static char spwbuf[BUFSIZ]; | ||
47 | static struct spwd spwd; | ||
48 | |||
49 | #define FIELDS 9 | ||
50 | #define OFIELDS 5 | ||
51 | |||
52 | /* setspent - initialize access to shadow text and DBM files */ | ||
53 | void 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 */ | ||
64 | void 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 */ | ||
72 | struct spwd *getspent(void) | ||
73 | { | ||
74 | if (!shadow) | ||
75 | setspent(); | ||
76 | return (fgetspent(shadow)); | ||
77 | } | ||
78 | |||
79 | /* getspnam - get a shadow entry by name */ | ||
80 | struct 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 */ | ||
99 | struct 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 */ | ||
252 | struct 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 | */ | ||
277 | int 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 | |||
20 | TOPDIR:= ../ | ||
21 | LOGINUTILS_DIR:=./ | ||
22 | include $(TOPDIR).config | ||
23 | include $(TOPDIR)Rules.mak | ||
24 | include Makefile.in | ||
25 | all: $(libraries-y) | ||
26 | -include $(TOPDIR).depend | ||
27 | |||
28 | clean: | ||
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 | |||
20 | LOGINUTILS_AR:=loginutils.a | ||
21 | ifndef LOGINUTILS_DIR | ||
22 | LOGINUTILS_DIR:=$(TOPDIR)loginutils/ | ||
23 | endif | ||
24 | |||
25 | LOGINUTILS-y:= | ||
26 | LOGINUTILS-$(CONFIG_ADDGROUP) += addgroup.o | ||
27 | LOGINUTILS-$(CONFIG_ADDUSER) += adduser.o | ||
28 | LOGINUTILS-$(CONFIG_DELUSER) += deluser.o | ||
29 | LOGINUTILS-$(CONFIG_GETTY) += getty.o | ||
30 | LOGINUTILS-$(CONFIG_LOGIN) += login.o tinylogin.o | ||
31 | LOGINUTILS-$(CONFIG_SU) += su.o tinylogin.o | ||
32 | |||
33 | libraries-y+=$(LOGINUTILS_DIR)$(LOGINUTILS_AR) | ||
34 | |||
35 | needcrypt-y:= | ||
36 | needcrypt-$(CONFIG_LOGIN) := y | ||
37 | needcrypt-$(CONFIG_SU) := y | ||
38 | |||
39 | ifeq ($(needcrypt-y),y) | ||
40 | libraries-y +=-lcrypt | ||
41 | endif | ||
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? */ | ||
47 | static 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 */ | ||
52 | static 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 */ | ||
89 | static 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 | * ________________________________________________________________________ */ | ||
136 | int 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 | |||
45 | typedef struct { | ||
46 | uid_t u; | ||
47 | gid_t g; | ||
48 | } Id; | ||
49 | |||
50 | /* data _____________________________ */ | ||
51 | |||
52 | /* defaults : should this be in an external file? */ | ||
53 | static const char default_passwd[] = "x"; | ||
54 | static const char default_gecos[] = "Linux User,,,"; | ||
55 | static const char default_home_prefix[] = "/home"; | ||
56 | static const char default_shell[] = "/bin/sh"; | ||
57 | |||
58 | #ifdef CONFIG_FEATURE_SHADOWPASSWDS | ||
59 | |||
60 | #include "shadow.h" | ||
61 | |||
62 | /* shadow in use? */ | ||
63 | static int shadow_enabled = 0; | ||
64 | #endif | ||
65 | |||
66 | /* remix */ | ||
67 | /* EDR recoded such that the uid may be passed in *p */ | ||
68 | static 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 | |||
118 | static 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 | |||
134 | static 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 | ||
151 | static 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 */ | ||
183 | static 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?) */ | ||
270 | static 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 | * ________________________________________________________________________ */ | ||
284 | int 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 | |||
6 | mainmenu_option next_comment | ||
7 | comment 'Login/Password Management Utilities' | ||
8 | |||
9 | |||
10 | bool 'addgroup' CONFIG_ADDGROUP | ||
11 | bool 'adduser' CONFIG_ADDUSER | ||
12 | bool 'deluser' CONFIG_DELUSER | ||
13 | bool 'delgroup' CONFIG_DELUSER | ||
14 | bool 'getty' CONFIG_GETTY | ||
15 | bool 'login' CONFIG_LOGIN | ||
16 | if [ "$CONFIG_LOGIN" = "y" ]; then | ||
17 | bool ' Support for /etc/securetty' CONFIG_FEATURE_SECURETTY | ||
18 | fi | ||
19 | bool 'su' CONFIG_SU | ||
20 | if [ "$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 | ||
22 | fi | ||
23 | |||
24 | endmenu | ||
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 */ | ||
38 | typedef 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. */ | ||
46 | static 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 */ | ||
71 | static 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 | /* ________________________________________________________________________ */ | ||
117 | int 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 | /* ________________________________________________________________________ */ | ||
143 | int 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 | |||
40 | extern 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 | |||
136 | struct 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 | |||
158 | struct 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 | |||
168 | struct 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 | |||
176 | struct Speedtab { | ||
177 | long speed; | ||
178 | int code; | ||
179 | }; | ||
180 | |||
181 | static 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 | |||
219 | static void parse_args(int argc, char **argv, struct options *op); | ||
220 | static void parse_speeds(struct options *op, char *arg); | ||
221 | static void update_utmp(char *line); | ||
222 | static void open_tty(char *tty, struct termio *tp, int local); | ||
223 | static void termio_init(struct termio *tp, int speed, struct options *op); | ||
224 | static void auto_baud(struct termio *tp); | ||
225 | static void do_prompt(struct options *op, struct termio *tp); | ||
226 | static void next_speed(struct termio *tp, struct options *op); | ||
227 | static char *get_logname(struct options *op, struct chardata *cp, | ||
228 | |||
229 | struct termio *tp); | ||
230 | static void termio_final(struct options *op, struct termio *tp, | ||
231 | |||
232 | struct chardata *cp); | ||
233 | static int caps_lock(const char *s); | ||
234 | static int bcode(const char *s); | ||
235 | static 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. */ | ||
240 | static char *fakehost = NULL; | ||
241 | |||
242 | /* ... */ | ||
243 | #ifdef DEBUGGING | ||
244 | #define debug(s) fprintf(dbf,s); fflush(dbf) | ||
245 | #define DEBUGTERM "/dev/ttyp0" | ||
246 | FILE *dbf; | ||
247 | #else | ||
248 | #define debug(s) /* nothing */ | ||
249 | #endif | ||
250 | |||
251 | int 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 | |||
376 | static 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 | |||
483 | static 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 */ | ||
500 | static 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 } */ | ||
553 | static 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 | |||
661 | static 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 */ | ||
700 | static 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 */ | ||
761 | static 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 */ | ||
902 | static 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 */ | ||
914 | static 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 */ | ||
1022 | static 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 */ | ||
1089 | static 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 */ | ||
1103 | static 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 | */ | ||
1121 | static 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 | ||
29 | static void checkutmp(int picky); | ||
30 | static void setutmp(const char *name, const char *line); | ||
31 | |||
32 | // import from encrypt.c | ||
33 | extern 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 */ | ||
47 | struct utmp utent; | ||
48 | |||
49 | |||
50 | static int check_nologin ( int amroot ); | ||
51 | |||
52 | #if defined CONFIG_FEATURE_SECURETTY | ||
53 | static int check_tty ( const char *tty ); | ||
54 | |||
55 | #else | ||
56 | static inline int check_tty ( const char *tty ) { return 1; } | ||
57 | |||
58 | #endif | ||
59 | |||
60 | static int is_my_tty ( const char *tty ); | ||
61 | static const char *login_prompt ( void ); | ||
62 | static void motd ( void ); | ||
63 | static void set_env(int argc, char *const *argv); | ||
64 | |||
65 | |||
66 | static void alarm_handler ( int sig ) | ||
67 | { | ||
68 | error_msg ( "\nLogin timed out after %d seconds.\n", TIMEOUT ); | ||
69 | exit ( EXIT_SUCCESS ); | ||
70 | } | ||
71 | |||
72 | |||
73 | extern 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 | |||
200 | auth_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 | |||
254 | static 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 | |||
277 | static 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 | |||
302 | static 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 */ | ||
335 | static 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 | |||
349 | static 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 | |||
385 | static 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 | */ | ||
430 | static 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 | |||
449 | static 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 | |||
40 | static 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 | |||
74 | int 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 | |||
52 | static 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 | |||
60 | void 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 | |||
77 | void 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 | |||
116 | int 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 | |||
132 | void 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 | |||
180 | int 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 | |||
4 | extern void change_identity ( const struct passwd *pw ); | ||
5 | extern void run_shell ( const char *shell, int loginshell, const char *command, char **additional_args ); | ||
6 | extern int restricted_shell ( const char *shell ); | ||
7 | extern void setup_environment ( const char *shell, int loginshell, int changeenv, const struct passwd *pw ); | ||
8 | extern int correct_password ( const struct passwd *pw ); | ||
9 | |||
10 | #endif | ||