1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 23*7c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 24*7c478bd9Sstevel@tonic-gate 25*7c478bd9Sstevel@tonic-gate /* 26*7c478bd9Sstevel@tonic-gate * Copyright (c) 2001 by Sun Microsystems, Inc. 27*7c478bd9Sstevel@tonic-gate * All rights reserved. 28*7c478bd9Sstevel@tonic-gate */ 29*7c478bd9Sstevel@tonic-gate 30*7c478bd9Sstevel@tonic-gate #ident "%Z%%M% %I% %E% SMI" /* from SVR4 bnu:expfile.c 2.10 */ 31*7c478bd9Sstevel@tonic-gate 32*7c478bd9Sstevel@tonic-gate #include "uucp.h" 33*7c478bd9Sstevel@tonic-gate 34*7c478bd9Sstevel@tonic-gate /* 35*7c478bd9Sstevel@tonic-gate * expand file name expansion is based on first characters 36*7c478bd9Sstevel@tonic-gate * / -> fully qualified pathname. no 37*7c478bd9Sstevel@tonic-gate * processing necessary 38*7c478bd9Sstevel@tonic-gate * ~ -> prepended with login directory 39*7c478bd9Sstevel@tonic-gate * ~/ -> prepended with Pubdir 40*7c478bd9Sstevel@tonic-gate * default -> prepended with current directory 41*7c478bd9Sstevel@tonic-gate * file -> filename to expand 42*7c478bd9Sstevel@tonic-gate * returns: 43*7c478bd9Sstevel@tonic-gate * 0 -> ok 44*7c478bd9Sstevel@tonic-gate * FAIL -> no Wrkdir name available 45*7c478bd9Sstevel@tonic-gate */ 46*7c478bd9Sstevel@tonic-gate int 47*7c478bd9Sstevel@tonic-gate expfile(file) 48*7c478bd9Sstevel@tonic-gate register char *file; 49*7c478bd9Sstevel@tonic-gate { 50*7c478bd9Sstevel@tonic-gate register char *fpart, *up; 51*7c478bd9Sstevel@tonic-gate uid_t uid; 52*7c478bd9Sstevel@tonic-gate char user[NAMESIZE], save[MAXFULLNAME]; 53*7c478bd9Sstevel@tonic-gate extern int gninfo(), canPath(); 54*7c478bd9Sstevel@tonic-gate 55*7c478bd9Sstevel@tonic-gate if (strlcpy(save, file, sizeof (save)) >= sizeof (save)) 56*7c478bd9Sstevel@tonic-gate return(FAIL); 57*7c478bd9Sstevel@tonic-gate if (*file != '/') 58*7c478bd9Sstevel@tonic-gate if (*file == '~') { 59*7c478bd9Sstevel@tonic-gate /* find / and copy user part */ 60*7c478bd9Sstevel@tonic-gate for (fpart = save + 1, up = user; *fpart != '\0' 61*7c478bd9Sstevel@tonic-gate && *fpart != '/'; fpart++) 62*7c478bd9Sstevel@tonic-gate *up++ = *fpart; 63*7c478bd9Sstevel@tonic-gate *up = '\0'; 64*7c478bd9Sstevel@tonic-gate if ((user[0]=='\0') || (gninfo(user, &uid, file) != 0)){ 65*7c478bd9Sstevel@tonic-gate (void) strcpy(file, Pubdir); 66*7c478bd9Sstevel@tonic-gate } 67*7c478bd9Sstevel@tonic-gate if (strlen(file) + strlen(fpart) + 1 > (unsigned)MAXFULLNAME) 68*7c478bd9Sstevel@tonic-gate return(FAIL); 69*7c478bd9Sstevel@tonic-gate (void) strcat(file, fpart); 70*7c478bd9Sstevel@tonic-gate } else { 71*7c478bd9Sstevel@tonic-gate if (strlen(Wrkdir) + strlen(save) + 2 > (unsigned)MAXFULLNAME) 72*7c478bd9Sstevel@tonic-gate return(FAIL); 73*7c478bd9Sstevel@tonic-gate (void) sprintf(file, "%s/%s", Wrkdir, save); 74*7c478bd9Sstevel@tonic-gate if (Wrkdir[0] == '\0') 75*7c478bd9Sstevel@tonic-gate return(FAIL); 76*7c478bd9Sstevel@tonic-gate } 77*7c478bd9Sstevel@tonic-gate 78*7c478bd9Sstevel@tonic-gate if (canPath(file) != 0) { /* I don't think this will ever fail */ 79*7c478bd9Sstevel@tonic-gate (void) strcpy(file, CORRUPTDIR); 80*7c478bd9Sstevel@tonic-gate return(FAIL); 81*7c478bd9Sstevel@tonic-gate } else 82*7c478bd9Sstevel@tonic-gate return(0); 83*7c478bd9Sstevel@tonic-gate } 84*7c478bd9Sstevel@tonic-gate 85*7c478bd9Sstevel@tonic-gate 86*7c478bd9Sstevel@tonic-gate /* 87*7c478bd9Sstevel@tonic-gate * make all necessary directories 88*7c478bd9Sstevel@tonic-gate * name -> directory to make 89*7c478bd9Sstevel@tonic-gate * mask -> mask to use during directory creation 90*7c478bd9Sstevel@tonic-gate * return: 91*7c478bd9Sstevel@tonic-gate * 0 -> success 92*7c478bd9Sstevel@tonic-gate * FAIL -> failure 93*7c478bd9Sstevel@tonic-gate */ 94*7c478bd9Sstevel@tonic-gate int 95*7c478bd9Sstevel@tonic-gate mkdirs(name, mask) 96*7c478bd9Sstevel@tonic-gate mode_t mask; 97*7c478bd9Sstevel@tonic-gate register char *name; 98*7c478bd9Sstevel@tonic-gate { 99*7c478bd9Sstevel@tonic-gate register char *p; 100*7c478bd9Sstevel@tonic-gate mode_t omask; 101*7c478bd9Sstevel@tonic-gate char dir[MAXFULLNAME]; 102*7c478bd9Sstevel@tonic-gate 103*7c478bd9Sstevel@tonic-gate strcpy(dir, name); 104*7c478bd9Sstevel@tonic-gate if (*LASTCHAR(dir) != '/') 105*7c478bd9Sstevel@tonic-gate (void) strcat(dir, "/"); 106*7c478bd9Sstevel@tonic-gate p = dir + 1; 107*7c478bd9Sstevel@tonic-gate for (;;) { 108*7c478bd9Sstevel@tonic-gate if ((p = strchr(p, '/')) == NULL) 109*7c478bd9Sstevel@tonic-gate return(0); 110*7c478bd9Sstevel@tonic-gate *p = '\0'; 111*7c478bd9Sstevel@tonic-gate if (DIRECTORY(dir)) { 112*7c478bd9Sstevel@tonic-gate /* if directory exists and is owned by uucp, child's 113*7c478bd9Sstevel@tonic-gate permissions should be no more open than parent */ 114*7c478bd9Sstevel@tonic-gate if (__s_.st_uid == UUCPUID) 115*7c478bd9Sstevel@tonic-gate mask |= ((~__s_.st_mode) & PUB_DIRMODE); 116*7c478bd9Sstevel@tonic-gate } else { 117*7c478bd9Sstevel@tonic-gate DEBUG(4, "mkdir - %s\n", dir); 118*7c478bd9Sstevel@tonic-gate omask = umask(mask); 119*7c478bd9Sstevel@tonic-gate if (mkdir(dir, PUB_DIRMODE) == FAIL) { 120*7c478bd9Sstevel@tonic-gate umask(omask); 121*7c478bd9Sstevel@tonic-gate return (FAIL); 122*7c478bd9Sstevel@tonic-gate } 123*7c478bd9Sstevel@tonic-gate umask(omask); 124*7c478bd9Sstevel@tonic-gate } 125*7c478bd9Sstevel@tonic-gate *p++ = '/'; 126*7c478bd9Sstevel@tonic-gate } 127*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 128*7c478bd9Sstevel@tonic-gate } 129*7c478bd9Sstevel@tonic-gate 130*7c478bd9Sstevel@tonic-gate /* 131*7c478bd9Sstevel@tonic-gate * expand file name and check return 132*7c478bd9Sstevel@tonic-gate * print error if it failed. 133*7c478bd9Sstevel@tonic-gate * file -> file name to check 134*7c478bd9Sstevel@tonic-gate * returns: 135*7c478bd9Sstevel@tonic-gate * 0 -> ok 136*7c478bd9Sstevel@tonic-gate * FAIL -> if expfile failed 137*7c478bd9Sstevel@tonic-gate */ 138*7c478bd9Sstevel@tonic-gate int 139*7c478bd9Sstevel@tonic-gate ckexpf(file) 140*7c478bd9Sstevel@tonic-gate char *file; 141*7c478bd9Sstevel@tonic-gate { 142*7c478bd9Sstevel@tonic-gate if (expfile(file) == 0) 143*7c478bd9Sstevel@tonic-gate return(0); 144*7c478bd9Sstevel@tonic-gate 145*7c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("Illegal filename (%s).\n"), file); 146*7c478bd9Sstevel@tonic-gate return(FAIL); 147*7c478bd9Sstevel@tonic-gate } 148*7c478bd9Sstevel@tonic-gate 149*7c478bd9Sstevel@tonic-gate 150*7c478bd9Sstevel@tonic-gate /* 151*7c478bd9Sstevel@tonic-gate * make canonical path out of path passed as argument. 152*7c478bd9Sstevel@tonic-gate * 153*7c478bd9Sstevel@tonic-gate * Eliminate redundant self-references like // or /./ 154*7c478bd9Sstevel@tonic-gate * (A single terminal / will be preserved, however.) 155*7c478bd9Sstevel@tonic-gate * Dispose of references to .. in the path names. 156*7c478bd9Sstevel@tonic-gate * In relative path names, this means that .. or a/../.. 157*7c478bd9Sstevel@tonic-gate * will be treated as an illegal reference. 158*7c478bd9Sstevel@tonic-gate * In full paths, .. is always allowed, with /.. treated as / 159*7c478bd9Sstevel@tonic-gate * 160*7c478bd9Sstevel@tonic-gate * returns: 161*7c478bd9Sstevel@tonic-gate * 0 -> path is now in canonical form 162*7c478bd9Sstevel@tonic-gate * FAIL -> relative path contained illegal .. reference 163*7c478bd9Sstevel@tonic-gate */ 164*7c478bd9Sstevel@tonic-gate 165*7c478bd9Sstevel@tonic-gate int 166*7c478bd9Sstevel@tonic-gate canPath(path) 167*7c478bd9Sstevel@tonic-gate register char *path; /* path is modified in place */ 168*7c478bd9Sstevel@tonic-gate { 169*7c478bd9Sstevel@tonic-gate register char *to, *fr; 170*7c478bd9Sstevel@tonic-gate 171*7c478bd9Sstevel@tonic-gate to = fr = path; 172*7c478bd9Sstevel@tonic-gate if (*fr == '/') *to++ = *fr++; 173*7c478bd9Sstevel@tonic-gate for (;;) { 174*7c478bd9Sstevel@tonic-gate /* skip past references to self and validate references to .. */ 175*7c478bd9Sstevel@tonic-gate for (;;) { 176*7c478bd9Sstevel@tonic-gate if (*fr == '/') { 177*7c478bd9Sstevel@tonic-gate fr++; 178*7c478bd9Sstevel@tonic-gate continue; 179*7c478bd9Sstevel@tonic-gate } 180*7c478bd9Sstevel@tonic-gate if ((strncmp(fr, "./", 2) == SAME) || EQUALS(fr, ".")) { 181*7c478bd9Sstevel@tonic-gate fr++; 182*7c478bd9Sstevel@tonic-gate continue; 183*7c478bd9Sstevel@tonic-gate } 184*7c478bd9Sstevel@tonic-gate if ((strncmp(fr, "../", 3) == SAME) || EQUALS(fr, "..")) { 185*7c478bd9Sstevel@tonic-gate fr += 2; 186*7c478bd9Sstevel@tonic-gate /* /.. is / */ 187*7c478bd9Sstevel@tonic-gate if (((to - 1) == path) && (*path == '/')) continue; 188*7c478bd9Sstevel@tonic-gate /* error if no previous component */ 189*7c478bd9Sstevel@tonic-gate if (to <= path) return (FAIL); 190*7c478bd9Sstevel@tonic-gate /* back past previous component */ 191*7c478bd9Sstevel@tonic-gate while ((--to > path) && (to[-1] != '/')); 192*7c478bd9Sstevel@tonic-gate continue; 193*7c478bd9Sstevel@tonic-gate } 194*7c478bd9Sstevel@tonic-gate break; 195*7c478bd9Sstevel@tonic-gate } 196*7c478bd9Sstevel@tonic-gate /* 197*7c478bd9Sstevel@tonic-gate * What follows is a legitimate component, 198*7c478bd9Sstevel@tonic-gate * terminated by a null or a / 199*7c478bd9Sstevel@tonic-gate */ 200*7c478bd9Sstevel@tonic-gate if (*fr == '\0') break; 201*7c478bd9Sstevel@tonic-gate while (((*to++ = *fr) != '\0') && (*fr++ != '/')); 202*7c478bd9Sstevel@tonic-gate } 203*7c478bd9Sstevel@tonic-gate /* null path is . */ 204*7c478bd9Sstevel@tonic-gate if (to == path) *to++ = '.'; 205*7c478bd9Sstevel@tonic-gate *to = '\0'; 206*7c478bd9Sstevel@tonic-gate return (0); 207*7c478bd9Sstevel@tonic-gate } 208