1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
3*0Sstevel@tonic-gate * Use is subject to license terms.
4*0Sstevel@tonic-gate */
5*0Sstevel@tonic-gate
6*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
7*0Sstevel@tonic-gate
8*0Sstevel@tonic-gate /****************************************************************************
9*0Sstevel@tonic-gate Copyright (c) 1999,2000 WU-FTPD Development Group.
10*0Sstevel@tonic-gate All rights reserved.
11*0Sstevel@tonic-gate
12*0Sstevel@tonic-gate Portions Copyright (c) 1980, 1985, 1988, 1989, 1990, 1991, 1993, 1994
13*0Sstevel@tonic-gate The Regents of the University of California.
14*0Sstevel@tonic-gate Portions Copyright (c) 1993, 1994 Washington University in Saint Louis.
15*0Sstevel@tonic-gate Portions Copyright (c) 1996, 1998 Berkeley Software Design, Inc.
16*0Sstevel@tonic-gate Portions Copyright (c) 1989 Massachusetts Institute of Technology.
17*0Sstevel@tonic-gate Portions Copyright (c) 1998 Sendmail, Inc.
18*0Sstevel@tonic-gate Portions Copyright (c) 1983, 1995, 1996, 1997 Eric P. Allman.
19*0Sstevel@tonic-gate Portions Copyright (c) 1997 by Stan Barber.
20*0Sstevel@tonic-gate Portions Copyright (c) 1997 by Kent Landfield.
21*0Sstevel@tonic-gate Portions Copyright (c) 1991, 1992, 1993, 1994, 1995, 1996, 1997
22*0Sstevel@tonic-gate Free Software Foundation, Inc.
23*0Sstevel@tonic-gate
24*0Sstevel@tonic-gate Use and distribution of this software and its source code are governed
25*0Sstevel@tonic-gate by the terms and conditions of the WU-FTPD Software License ("LICENSE").
26*0Sstevel@tonic-gate
27*0Sstevel@tonic-gate If you did not receive a copy of the license, it may be obtained online
28*0Sstevel@tonic-gate at http://www.wu-ftpd.org/license.html.
29*0Sstevel@tonic-gate
30*0Sstevel@tonic-gate $Id: private.c,v 1.12 2000/07/01 18:17:39 wuftpd Exp $
31*0Sstevel@tonic-gate
32*0Sstevel@tonic-gate ****************************************************************************/
33*0Sstevel@tonic-gate #include "config.h"
34*0Sstevel@tonic-gate
35*0Sstevel@tonic-gate #ifndef NO_PRIVATE
36*0Sstevel@tonic-gate
37*0Sstevel@tonic-gate #include <stdio.h>
38*0Sstevel@tonic-gate #include <errno.h>
39*0Sstevel@tonic-gate
40*0Sstevel@tonic-gate extern char *strsep(char **, const char *);
41*0Sstevel@tonic-gate
42*0Sstevel@tonic-gate #include <string.h>
43*0Sstevel@tonic-gate #ifdef HAVE_SYS_SYSLOG_H
44*0Sstevel@tonic-gate #include <sys/syslog.h>
45*0Sstevel@tonic-gate #endif
46*0Sstevel@tonic-gate #if defined(HAVE_SYSLOG_H) || (!defined(AUTOCONF) && !defined(HAVE_SYS_SYSLOG_H))
47*0Sstevel@tonic-gate #include <syslog.h>
48*0Sstevel@tonic-gate #endif
49*0Sstevel@tonic-gate #include <grp.h>
50*0Sstevel@tonic-gate
51*0Sstevel@tonic-gate #include <sys/types.h>
52*0Sstevel@tonic-gate #include <sys/stat.h>
53*0Sstevel@tonic-gate #include <sys/file.h>
54*0Sstevel@tonic-gate
55*0Sstevel@tonic-gate #ifdef HAVE_PATHS_H
56*0Sstevel@tonic-gate #include <paths.h>
57*0Sstevel@tonic-gate #endif
58*0Sstevel@tonic-gate #include "pathnames.h"
59*0Sstevel@tonic-gate #include "extensions.h"
60*0Sstevel@tonic-gate #include "proto.h"
61*0Sstevel@tonic-gate
62*0Sstevel@tonic-gate #ifdef SECUREOSF
63*0Sstevel@tonic-gate #define SecureWare /* Does this mean it works for all SecureWare? */
64*0Sstevel@tonic-gate #endif
65*0Sstevel@tonic-gate
66*0Sstevel@tonic-gate #ifdef HPUX_10_TRUSTED
67*0Sstevel@tonic-gate #include <hpsecurity.h>
68*0Sstevel@tonic-gate #endif
69*0Sstevel@tonic-gate
70*0Sstevel@tonic-gate #if defined(SecureWare) || defined(HPUX_10_TRUSTED)
71*0Sstevel@tonic-gate #include <prot.h>
72*0Sstevel@tonic-gate #endif
73*0Sstevel@tonic-gate
74*0Sstevel@tonic-gate #ifndef NO_CRYPT_PROTO
75*0Sstevel@tonic-gate extern char *crypt(const char *, const char *);
76*0Sstevel@tonic-gate #endif
77*0Sstevel@tonic-gate
78*0Sstevel@tonic-gate static int group_attempts, group_given;
79*0Sstevel@tonic-gate static char *groupname, *passbuf;
80*0Sstevel@tonic-gate
81*0Sstevel@tonic-gate struct acgrp {
82*0Sstevel@tonic-gate char *gname; /* access group name */
83*0Sstevel@tonic-gate char *gpass; /* access group password */
84*0Sstevel@tonic-gate gid_t gr_gid; /* group to setegid() to */
85*0Sstevel@tonic-gate struct acgrp *next;
86*0Sstevel@tonic-gate };
87*0Sstevel@tonic-gate
88*0Sstevel@tonic-gate static struct acgrp *privptr, *privtail;
89*0Sstevel@tonic-gate
90*0Sstevel@tonic-gate extern int lgi_failure_threshold;
91*0Sstevel@tonic-gate extern char remoteident[];
92*0Sstevel@tonic-gate
add_acgrp(char * gname,char * gpass,gid_t gid)93*0Sstevel@tonic-gate static void add_acgrp(char *gname, char *gpass, gid_t gid)
94*0Sstevel@tonic-gate {
95*0Sstevel@tonic-gate struct acgrp *aptr;
96*0Sstevel@tonic-gate
97*0Sstevel@tonic-gate aptr = (struct acgrp *) calloc(1, sizeof(struct acgrp));
98*0Sstevel@tonic-gate if (aptr == NULL) {
99*0Sstevel@tonic-gate syslog(LOG_ERR, "calloc error in add_acgrp");
100*0Sstevel@tonic-gate dologout(1);
101*0Sstevel@tonic-gate }
102*0Sstevel@tonic-gate
103*0Sstevel@tonic-gate /* add element to end of list */
104*0Sstevel@tonic-gate if (privtail)
105*0Sstevel@tonic-gate privtail->next = aptr;
106*0Sstevel@tonic-gate privtail = aptr;
107*0Sstevel@tonic-gate if (!privptr)
108*0Sstevel@tonic-gate privptr = aptr;
109*0Sstevel@tonic-gate
110*0Sstevel@tonic-gate aptr->gname = strdup(gname);
111*0Sstevel@tonic-gate if (aptr->gname == NULL) {
112*0Sstevel@tonic-gate syslog(LOG_ERR, "malloc error in add_acgrp");
113*0Sstevel@tonic-gate dologout(1);
114*0Sstevel@tonic-gate }
115*0Sstevel@tonic-gate if (gpass == NULL)
116*0Sstevel@tonic-gate aptr->gpass = strdup("");
117*0Sstevel@tonic-gate else
118*0Sstevel@tonic-gate aptr->gpass = strdup(gpass);
119*0Sstevel@tonic-gate if (aptr->gpass == NULL) {
120*0Sstevel@tonic-gate syslog(LOG_ERR, "malloc error in add_acgrp");
121*0Sstevel@tonic-gate dologout(1);
122*0Sstevel@tonic-gate }
123*0Sstevel@tonic-gate aptr->gr_gid = gid;
124*0Sstevel@tonic-gate }
125*0Sstevel@tonic-gate
parsepriv(void)126*0Sstevel@tonic-gate static void parsepriv(void)
127*0Sstevel@tonic-gate {
128*0Sstevel@tonic-gate char *ptr;
129*0Sstevel@tonic-gate char *acptr = passbuf, *line;
130*0Sstevel@tonic-gate char *argv[3], *p, *val;
131*0Sstevel@tonic-gate struct group *gr;
132*0Sstevel@tonic-gate int n;
133*0Sstevel@tonic-gate
134*0Sstevel@tonic-gate if (!passbuf || !(*passbuf))
135*0Sstevel@tonic-gate return;
136*0Sstevel@tonic-gate
137*0Sstevel@tonic-gate /* read through passbuf, stripping comments. */
138*0Sstevel@tonic-gate while (*acptr != '\0') {
139*0Sstevel@tonic-gate line = acptr;
140*0Sstevel@tonic-gate while (*acptr && *acptr != '\n')
141*0Sstevel@tonic-gate acptr++;
142*0Sstevel@tonic-gate *acptr++ = '\0';
143*0Sstevel@tonic-gate
144*0Sstevel@tonic-gate /* deal with comments */
145*0Sstevel@tonic-gate if ((ptr = strchr(line, '#')) != NULL)
146*0Sstevel@tonic-gate *ptr = '\0';
147*0Sstevel@tonic-gate
148*0Sstevel@tonic-gate if (*line == '\0')
149*0Sstevel@tonic-gate continue;
150*0Sstevel@tonic-gate
151*0Sstevel@tonic-gate /* parse the lines... */
152*0Sstevel@tonic-gate for (n = 0, p = line; n < 3 && p != NULL; n++) {
153*0Sstevel@tonic-gate val = (char *) strsep(&p, ":\n");
154*0Sstevel@tonic-gate argv[n] = val;
155*0Sstevel@tonic-gate if ((argv[n][0] == ' ') || (argv[n][0] == '\0'))
156*0Sstevel@tonic-gate argv[n] = NULL;
157*0Sstevel@tonic-gate }
158*0Sstevel@tonic-gate /* check their were 3 fields, if not skip the line... */
159*0Sstevel@tonic-gate if (n != 3 || p != NULL)
160*0Sstevel@tonic-gate continue;
161*0Sstevel@tonic-gate
162*0Sstevel@tonic-gate if (argv[0] && argv[2]) {
163*0Sstevel@tonic-gate if (argv[2][0] == '%') {
164*0Sstevel@tonic-gate gid_t gid = atoi(argv[2] + 1);
165*0Sstevel@tonic-gate if ((gr = getgrgid(gid)) != NULL)
166*0Sstevel@tonic-gate add_acgrp(argv[0], argv[1], gid);
167*0Sstevel@tonic-gate }
168*0Sstevel@tonic-gate else {
169*0Sstevel@tonic-gate if ((gr = getgrnam((char *) argv[2])) != NULL)
170*0Sstevel@tonic-gate add_acgrp(argv[0], argv[1], gr->gr_gid);
171*0Sstevel@tonic-gate }
172*0Sstevel@tonic-gate endgrent();
173*0Sstevel@tonic-gate }
174*0Sstevel@tonic-gate }
175*0Sstevel@tonic-gate }
176*0Sstevel@tonic-gate
177*0Sstevel@tonic-gate /*************************************************************************/
178*0Sstevel@tonic-gate /* FUNCTION : priv_setup */
179*0Sstevel@tonic-gate /* PURPOSE : Set things up to use the private access password file. */
180*0Sstevel@tonic-gate /* ARGUMENTS : path, the path to the private access password file */
181*0Sstevel@tonic-gate /*************************************************************************/
182*0Sstevel@tonic-gate
priv_setup(char * path)183*0Sstevel@tonic-gate void priv_setup(char *path)
184*0Sstevel@tonic-gate {
185*0Sstevel@tonic-gate FILE *prvfile;
186*0Sstevel@tonic-gate struct stat finfo;
187*0Sstevel@tonic-gate struct acgrp *aptr;
188*0Sstevel@tonic-gate
189*0Sstevel@tonic-gate while (privptr) {
190*0Sstevel@tonic-gate aptr = privptr->next;
191*0Sstevel@tonic-gate free(privptr->gname);
192*0Sstevel@tonic-gate free(privptr->gpass);
193*0Sstevel@tonic-gate free(privptr);
194*0Sstevel@tonic-gate privptr = aptr;
195*0Sstevel@tonic-gate }
196*0Sstevel@tonic-gate privtail = NULL;
197*0Sstevel@tonic-gate
198*0Sstevel@tonic-gate if (passbuf) {
199*0Sstevel@tonic-gate free(passbuf);
200*0Sstevel@tonic-gate passbuf = NULL;
201*0Sstevel@tonic-gate }
202*0Sstevel@tonic-gate
203*0Sstevel@tonic-gate if ((prvfile = fopen(path, "r")) == NULL) {
204*0Sstevel@tonic-gate if (errno != ENOENT)
205*0Sstevel@tonic-gate syslog(LOG_ERR, "cannot open private access file %s: %s",
206*0Sstevel@tonic-gate path, strerror(errno));
207*0Sstevel@tonic-gate return;
208*0Sstevel@tonic-gate }
209*0Sstevel@tonic-gate if (fstat(fileno(prvfile), &finfo) != 0) {
210*0Sstevel@tonic-gate syslog(LOG_ERR, "cannot fstat private access file %s: %s", path,
211*0Sstevel@tonic-gate strerror(errno));
212*0Sstevel@tonic-gate (void) fclose(prvfile);
213*0Sstevel@tonic-gate return;
214*0Sstevel@tonic-gate }
215*0Sstevel@tonic-gate if (finfo.st_size == 0) {
216*0Sstevel@tonic-gate passbuf = (char *) calloc(1, 1);
217*0Sstevel@tonic-gate }
218*0Sstevel@tonic-gate else {
219*0Sstevel@tonic-gate if (!(passbuf = (char *) malloc((size_t) finfo.st_size + 1))) {
220*0Sstevel@tonic-gate (void) syslog(LOG_ERR, "could not malloc passbuf (%d bytes)",
221*0Sstevel@tonic-gate (size_t) finfo.st_size + 1);
222*0Sstevel@tonic-gate (void) fclose(prvfile);
223*0Sstevel@tonic-gate return;
224*0Sstevel@tonic-gate }
225*0Sstevel@tonic-gate if (!fread(passbuf, (size_t) finfo.st_size, 1, prvfile)) {
226*0Sstevel@tonic-gate (void) syslog(LOG_ERR, "error reading private access file %s: %s",
227*0Sstevel@tonic-gate path, strerror(errno));
228*0Sstevel@tonic-gate (void) fclose(prvfile);
229*0Sstevel@tonic-gate return;
230*0Sstevel@tonic-gate }
231*0Sstevel@tonic-gate *(passbuf + finfo.st_size) = '\0';
232*0Sstevel@tonic-gate }
233*0Sstevel@tonic-gate (void) fclose(prvfile);
234*0Sstevel@tonic-gate (void) parsepriv();
235*0Sstevel@tonic-gate }
236*0Sstevel@tonic-gate
237*0Sstevel@tonic-gate /*************************************************************************/
238*0Sstevel@tonic-gate /* FUNCTION : priv_getent */
239*0Sstevel@tonic-gate /* PURPOSE : Retrieve an entry from the in-memory copy of the group */
240*0Sstevel@tonic-gate /* access file. */
241*0Sstevel@tonic-gate /* ARGUMENTS : pointer to group name */
242*0Sstevel@tonic-gate /*************************************************************************/
243*0Sstevel@tonic-gate
priv_getent(char * group)244*0Sstevel@tonic-gate static struct acgrp *priv_getent(char *group)
245*0Sstevel@tonic-gate {
246*0Sstevel@tonic-gate struct acgrp *ptr;
247*0Sstevel@tonic-gate
248*0Sstevel@tonic-gate for (ptr = privptr; ptr; ptr = ptr->next)
249*0Sstevel@tonic-gate if (!strcasecmp(group, ptr->gname))
250*0Sstevel@tonic-gate return (ptr);
251*0Sstevel@tonic-gate
252*0Sstevel@tonic-gate return (NULL);
253*0Sstevel@tonic-gate }
254*0Sstevel@tonic-gate
255*0Sstevel@tonic-gate /*************************************************************************/
256*0Sstevel@tonic-gate /* FUNCTION : priv_group */
257*0Sstevel@tonic-gate /* PURPOSE : */
258*0Sstevel@tonic-gate /* ARGUMENTS : */
259*0Sstevel@tonic-gate /*************************************************************************/
260*0Sstevel@tonic-gate
priv_group(char * group)261*0Sstevel@tonic-gate void priv_group(char *group)
262*0Sstevel@tonic-gate {
263*0Sstevel@tonic-gate if (groupname)
264*0Sstevel@tonic-gate free(groupname);
265*0Sstevel@tonic-gate
266*0Sstevel@tonic-gate groupname = strdup(group);
267*0Sstevel@tonic-gate if (groupname == NULL) {
268*0Sstevel@tonic-gate reply(421, "Local resource failure: malloc");
269*0Sstevel@tonic-gate syslog(LOG_ERR, "malloc error in priv_group");
270*0Sstevel@tonic-gate dologout(1);
271*0Sstevel@tonic-gate }
272*0Sstevel@tonic-gate group_given = 1;
273*0Sstevel@tonic-gate reply(200, "Request for access to group %s accepted.", group);
274*0Sstevel@tonic-gate }
275*0Sstevel@tonic-gate
276*0Sstevel@tonic-gate /*************************************************************************/
277*0Sstevel@tonic-gate /* FUNCTION : priv_gpass */
278*0Sstevel@tonic-gate /* PURPOSE : validate the group access request, and if OK place user */
279*0Sstevel@tonic-gate /* in the proper group. */
280*0Sstevel@tonic-gate /* ARGUMENTS : group access password */
281*0Sstevel@tonic-gate /*************************************************************************/
282*0Sstevel@tonic-gate
priv_gpass(char * gpass)283*0Sstevel@tonic-gate void priv_gpass(char *gpass)
284*0Sstevel@tonic-gate {
285*0Sstevel@tonic-gate char *xgpass = NULL;
286*0Sstevel@tonic-gate struct acgrp *grp;
287*0Sstevel@tonic-gate uid_t uid;
288*0Sstevel@tonic-gate
289*0Sstevel@tonic-gate if (group_given == 0) {
290*0Sstevel@tonic-gate reply(503, "Give group name with SITE GROUP first.");
291*0Sstevel@tonic-gate return;
292*0Sstevel@tonic-gate }
293*0Sstevel@tonic-gate /* OK, now they're getting a chance to specify a password. Make them
294*0Sstevel@tonic-gate * give the group name again if they fail... */
295*0Sstevel@tonic-gate group_given = 0;
296*0Sstevel@tonic-gate
297*0Sstevel@tonic-gate grp = priv_getent(groupname);
298*0Sstevel@tonic-gate if (passbuf && gpass && *gpass != '\0' && grp && *grp->gpass != '\0')
299*0Sstevel@tonic-gate #if defined(SecureWare) || defined(HPUX_10_TRUSTED)
300*0Sstevel@tonic-gate xgpass = bigcrypt(gpass, grp->gpass);
301*0Sstevel@tonic-gate #else
302*0Sstevel@tonic-gate xgpass = crypt(gpass, grp->gpass);
303*0Sstevel@tonic-gate #endif
304*0Sstevel@tonic-gate
305*0Sstevel@tonic-gate if (!(((gpass != NULL)
306*0Sstevel@tonic-gate && (*gpass != '\0')
307*0Sstevel@tonic-gate && (grp != NULL)
308*0Sstevel@tonic-gate && (*grp->gpass != '\0')
309*0Sstevel@tonic-gate && (strcmp(xgpass, grp->gpass) == 0))
310*0Sstevel@tonic-gate || (((gpass == NULL)
311*0Sstevel@tonic-gate || (*gpass == '\0'))
312*0Sstevel@tonic-gate && (grp != NULL)
313*0Sstevel@tonic-gate && (*grp->gpass == '\0'))
314*0Sstevel@tonic-gate )) {
315*0Sstevel@tonic-gate reply(530, "Group access request incorrect.");
316*0Sstevel@tonic-gate grp = NULL;
317*0Sstevel@tonic-gate if (++group_attempts >= lgi_failure_threshold) {
318*0Sstevel@tonic-gate syslog(LOG_NOTICE,
319*0Sstevel@tonic-gate "repeated group access failures from %s, group %s",
320*0Sstevel@tonic-gate remoteident, groupname);
321*0Sstevel@tonic-gate dologout(0);
322*0Sstevel@tonic-gate }
323*0Sstevel@tonic-gate sleep(group_attempts); /* slow down password crackers */
324*0Sstevel@tonic-gate return;
325*0Sstevel@tonic-gate }
326*0Sstevel@tonic-gate
327*0Sstevel@tonic-gate uid = geteuid();
328*0Sstevel@tonic-gate setid_priv_on(0);
329*0Sstevel@tonic-gate setegid(grp->gr_gid);
330*0Sstevel@tonic-gate setid_priv_off(uid);
331*0Sstevel@tonic-gate
332*0Sstevel@tonic-gate reply(200, "Group access enabled.");
333*0Sstevel@tonic-gate group_attempts = 0;
334*0Sstevel@tonic-gate }
335*0Sstevel@tonic-gate #endif /* !NO_PRIVATE */
336