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