2
* uucpd.c Designed to be run from inetd. Checks loginname/password,
3
* also checks if this _really_ is a uucp login.
4
* Does utmp/wtmp accounting.
6
* Version: @(#)uucpd.c 1.00 19-May-1998 miquels@cistron.nl
7
* Version: @(#)uucpd.c 1.10 28-Jul-2001 alex@king.net.nz
10
#include <sys/types.h>
25
#include <security/pam_appl.h>
26
#include <security/pam_misc.h>
28
#include <sys/socket.h>
29
#include <netinet/in.h>
30
#include <arpa/inet.h>
33
int myconv(int n,const struct pam_message **msg, struct pam_response **resp, void *ap)
38
rv=misc_conv(n,msg,resp,ap);
39
if (rv != PAM_SUCCESS)
42
* The supplied misc_conv function doesn't seem to strip the
43
* trailing return character so I do it here...
46
for (cp=((*resp)->resp);*cp!=0;cp++)
51
static struct pam_conv conv = {
61
if (*p == '\r' || *p == '\n') {
69
* Read one line from the input.
71
int getstr(int fd, char *buf, int len)
79
if ((n = read(fd, buf + cnt, len - cnt)) <= 0) {
80
if (n == -1 && errno == EINTR)
85
for(i = 0; i < cnt; i++) {
86
if (buf[i] == '\r' || buf[i] == '\n') {
91
if (cnt >= len) break;
94
return cnt > 0 ? cnt : n;
100
char login[UT_NAMESIZE];
101
char host[UT_HOSTSIZE];
104
struct sockaddr_in sin;
111
pam_handle_t *pamh=NULL;
114
* Make sure we have fds 0, 1 and 2.
120
openlog("uucpd", LOG_PID, LOG_UUCP);
123
* Get the remote host address.
125
sinlen = sizeof(sin);
126
if (getpeername(0, (struct sockaddr *)&sin, &sinlen) < 0) {
127
syslog(LOG_ERR, "getpeername: %m");
130
if ((h = gethostbyaddr((char *)&sin.sin_addr,
131
sizeof(sin.sin_addr), AF_INET)) != NULL) {
132
strncpy(host, h->h_name, sizeof(host));
133
host[sizeof(host) - 1] = 0;
135
strcpy(host, inet_ntoa(sin.sin_addr));
144
if (getstr(0, login, sizeof(login)) < 0)
146
login[sizeof(login) - 1] = 0;
148
if (login[0] != 0) break;
151
rv=pam_start("uucp",login,&conv,&pamh);
153
rv=pam_authenticate(pamh, 0);
155
rv=pam_set_item(pamh,PAM_RHOST,host);
157
rv=pam_acct_mgmt(pamh,0);
158
if (rv!=PAM_SUCCESS) {
159
syslog(LOG_AUTHPRIV|LOG_NOTICE,pam_strerror(pamh,rv));
162
if ((pwd = getpwnam(login)) == NULL) {
164
syslog(LOG_AUTHPRIV|LOG_NOTICE,
165
"invalid password for `%s' on `TCP' from `%s'",
167
printf("Login incorrect.\r\n");
172
* See if we have a valid shell: the basename must
175
* Note: arguably this check should be done by PAM, but
176
* an appropriate PAM module doesn't exist to my knowledge.
178
if ((s = strrchr(pwd->pw_shell, '/')) == NULL)
182
if (strncmp(s, "uucico", 6) != 0) {
183
syslog(LOG_AUTHPRIV|LOG_NOTICE,
184
"invalid shell for `%s' on `TCP' from `%s'",
186
printf("Invalid shell (not uucico)\r\n");
191
* Allright we can assume the rest will go OK.
193
memset(&ut, 0, sizeof(ut));
194
ut.ut_type = LOGIN_PROCESS;
195
strncpy(ut.ut_user, login, sizeof(ut.ut_user));
196
strncpy(ut.ut_host, host, sizeof(ut.ut_host));
197
ut.ut_addr = sin.sin_addr.s_addr;
198
ut.ut_time = time(NULL);
201
* Fork, let the parent wait to write the utmp file.
203
signal(SIGHUP, SIG_IGN);
204
if ((pid = fork()) != 0) {
207
/* FIXME: SCREAM (oh well..) */
210
pam_open_session(pamh, 0);
213
sprintf(ut.ut_line, "uucp%d", ut.ut_pid);
214
snprintf(ut.ut_id, sizeof(ut.ut_id), "uu%02x", ut.ut_pid&0xff);
217
updwtmp(WTMP_FILE, &ut);
219
while(wait(&st) != pid);
222
ut.ut_type = DEAD_PROCESS;
223
ut.ut_time = time(NULL);
227
updwtmp(WTMP_FILE, &ut);
228
pam_close_session(pamh, 0);
229
pam_end(pamh,PAM_SUCCESS);
235
* This is the child - exec uucico.
237
signal(SIGHUP, SIG_DFL);
238
if (chdir(pwd->pw_dir) != 0) {
242
if (setgid(pwd->pw_gid) != 0) {
246
if (initgroups(pwd->pw_name, pwd->pw_gid) < 0) {
247
perror("initgroups");
250
if (setuid(pwd->pw_uid) != 0) {
254
setenv("LOGNAME", pwd->pw_name, 1);
255
setenv("USER", pwd->pw_name, 1);
256
setenv("SHELL", pwd->pw_shell, 1);
257
setenv("TERM", "dumb", 1);
260
execl(pwd->pw_shell, pwd->pw_shell, NULL);
262
perror(pwd->pw_shell);