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 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 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 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 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 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 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 */