xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.sbin/in.ftpd/private.c (revision 0:68f95e015346)
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