1*13638Ssam #ifndef lint 2*13638Ssam static char sccsid[] = "@(#)chkpth.c 5.1 (Berkeley) 07/02/83"; 3*13638Ssam #endif 4*13638Ssam 5*13638Ssam /* 6*13638Ssam * Doug Kingston, 30 July 82 to fix handling of the "userpath" structures. 7*13638Ssam * (brl-bmd) 8*13638Ssam * rti!trt: the code here is bizarre. There must be a zillion holes. 9*13638Ssam * chkpth should not be called for implied Spool requests . 10*13638Ssam * But explicit requests (foo!/usr/spoo/uucp/*) should use chkpth. 11*13638Ssam */ 12*13638Ssam #include "uucp.h" 13*13638Ssam #include <sys/types.h> 14*13638Ssam #include <sys/stat.h> 15*13638Ssam 16*13638Ssam 17*13638Ssam struct userpath { 18*13638Ssam char *us_lname; 19*13638Ssam char *us_mname; 20*13638Ssam char us_callback; 21*13638Ssam char **us_path; 22*13638Ssam struct userpath *unext; 23*13638Ssam }; 24*13638Ssam struct userpath *Uhead = NULL; 25*13638Ssam struct userpath *Mchdef = NULL, *Logdef = NULL; 26*13638Ssam int Uptfirst = 1; 27*13638Ssam 28*13638Ssam 29*13638Ssam /******* 30*13638Ssam * chkpth(logname, mchname, path) 31*13638Ssam * char *path, *logname, *mchname; 32*13638Ssam * 33*13638Ssam * chkpth - this routine will check the path table for the 34*13638Ssam * machine or log name (non-null parameter) to see if the 35*13638Ssam * input path (path) 36*13638Ssam * starts with an acceptable prefix. 37*13638Ssam * 38*13638Ssam * return codes: 0 | FAIL 39*13638Ssam */ 40*13638Ssam 41*13638Ssam chkpth(logname, mchname, path) 42*13638Ssam char *path, *logname, *mchname; 43*13638Ssam { 44*13638Ssam register struct userpath *u; 45*13638Ssam extern char *lastpart(); 46*13638Ssam register char **p, *s; 47*13638Ssam 48*13638Ssam /* Allow only rooted pathnames. Security wish. rti!trt */ 49*13638Ssam if (*path != '/') 50*13638Ssam return(FAIL); 51*13638Ssam 52*13638Ssam if (Uptfirst) { 53*13638Ssam rdpth(); 54*13638Ssam ASSERT(Uhead != NULL, "INIT USERFILE, No entrys!", "", 0); 55*13638Ssam Uptfirst = 0; 56*13638Ssam } 57*13638Ssam for (u = Uhead; u != NULL; ) { 58*13638Ssam if (*logname != '\0' && strcmp(logname, u->us_lname) == SAME) 59*13638Ssam break; 60*13638Ssam if (*mchname != '\0' && strncmp(mchname, u->us_mname, 7) == SAME) 61*13638Ssam break; 62*13638Ssam u = u->unext; 63*13638Ssam } 64*13638Ssam if (u == NULL) { 65*13638Ssam if (*logname == '\0') 66*13638Ssam u = Mchdef; 67*13638Ssam else 68*13638Ssam u = Logdef; 69*13638Ssam if (u == NULL) 70*13638Ssam return(FAIL); 71*13638Ssam } 72*13638Ssam /* found user name */ 73*13638Ssam p = u->us_path; 74*13638Ssam 75*13638Ssam /* check for /../ in path name */ 76*13638Ssam for (s = path; *s != '\0'; s++) { 77*13638Ssam if (prefix("/../",s)) 78*13638Ssam return(FAIL); 79*13638Ssam } 80*13638Ssam 81*13638Ssam /* Check for access permission */ 82*13638Ssam for (p = u->us_path; *p != NULL; p++) 83*13638Ssam if (prefix(*p, path)) 84*13638Ssam return(0); 85*13638Ssam 86*13638Ssam /* path name not valid */ 87*13638Ssam return(FAIL); 88*13638Ssam } 89*13638Ssam 90*13638Ssam 91*13638Ssam /*** 92*13638Ssam * rdpth() 93*13638Ssam * 94*13638Ssam * rdpth - this routine will read the USERFILE and 95*13638Ssam * construct the userpath structure pointed to by (u); 96*13638Ssam * 97*13638Ssam * return codes: 0 | FAIL 98*13638Ssam * 99*13638Ssam * 5/3/81 - changed to enforce the uucp-wide convention that system 100*13638Ssam * names be 7 chars or less in length 101*13638Ssam */ 102*13638Ssam 103*13638Ssam rdpth() 104*13638Ssam { 105*13638Ssam char buf[100 + 1], *pbuf[50 + 1]; 106*13638Ssam register struct userpath *u; 107*13638Ssam register char *pc, **cp; 108*13638Ssam FILE *uf; 109*13638Ssam 110*13638Ssam if ((uf = fopen(USERFILE, "r")) == NULL) { 111*13638Ssam /* can not open file */ 112*13638Ssam return; 113*13638Ssam } 114*13638Ssam 115*13638Ssam while (cfgets(buf, sizeof(buf), uf) != NULL) { 116*13638Ssam int nargs, i; 117*13638Ssam 118*13638Ssam if ((u = (struct userpath *)malloc(sizeof (struct userpath))) == NULL) { 119*13638Ssam DEBUG (1, "*** Userpath malloc failed\n", 0); 120*13638Ssam fclose (uf); 121*13638Ssam return; 122*13638Ssam } 123*13638Ssam if ((pc = calloc((unsigned)strlen(buf) + 1, sizeof (char))) 124*13638Ssam == NULL) { 125*13638Ssam /* can not allocate space */ 126*13638Ssam DEBUG (1, "Userpath calloc 1 failed\n", 0); 127*13638Ssam fclose(uf); 128*13638Ssam return; 129*13638Ssam } 130*13638Ssam 131*13638Ssam strcpy(pc, buf); 132*13638Ssam nargs = getargs(pc, pbuf); 133*13638Ssam u->us_lname = pbuf[0]; 134*13638Ssam pc = index(u->us_lname, ','); 135*13638Ssam if (pc != NULL) 136*13638Ssam *pc++ = '\0'; 137*13638Ssam else 138*13638Ssam pc = u->us_lname + strlen(u->us_lname); 139*13638Ssam u->us_mname = pc; 140*13638Ssam if (strlen(u->us_mname) > 7) 141*13638Ssam u->us_mname[7] = '\0'; 142*13638Ssam if (*u->us_lname == '\0' && Logdef == NULL) 143*13638Ssam Logdef = u; 144*13638Ssam /* rti!trt: commented following else so 145*13638Ssam * chkpth("","",file) works okay. 146*13638Ssam * I don't understand this, though. 147*13638Ssam */ 148*13638Ssam /*else*/ if (*u->us_mname == '\0' && Mchdef == NULL) 149*13638Ssam Mchdef = u; 150*13638Ssam i = 1; 151*13638Ssam if (strcmp(pbuf[1], "c") == SAME) { 152*13638Ssam u->us_callback = 1; 153*13638Ssam i++; 154*13638Ssam } 155*13638Ssam else 156*13638Ssam u->us_callback = 0; 157*13638Ssam if ((cp = u->us_path = 158*13638Ssam (char **)calloc((unsigned)(nargs-i+1), sizeof(char *))) == NULL) { 159*13638Ssam /* can not allocate space */ 160*13638Ssam DEBUG (1, "Userpath calloc 2 failed!\n", 0); 161*13638Ssam fclose(uf); 162*13638Ssam return; 163*13638Ssam } 164*13638Ssam 165*13638Ssam while (i < nargs) 166*13638Ssam *cp++ = pbuf[i++]; 167*13638Ssam *cp = NULL; 168*13638Ssam u->unext = Uhead; 169*13638Ssam Uhead = u; 170*13638Ssam } 171*13638Ssam 172*13638Ssam fclose(uf); 173*13638Ssam return; 174*13638Ssam } 175*13638Ssam 176*13638Ssam /*** 177*13638Ssam * callback(name) check for callback 178*13638Ssam * char *name; 179*13638Ssam * 180*13638Ssam * return codes: 181*13638Ssam * 0 - no call back 182*13638Ssam * 1 - call back 183*13638Ssam */ 184*13638Ssam 185*13638Ssam callback(name) 186*13638Ssam register char *name; 187*13638Ssam { 188*13638Ssam register struct userpath *u; 189*13638Ssam 190*13638Ssam if (Uptfirst) { 191*13638Ssam rdpth(); 192*13638Ssam ASSERT(Uhead != NULL, "INIT USERFILE, No Users!", "", 0); 193*13638Ssam Uptfirst = 0; 194*13638Ssam } 195*13638Ssam 196*13638Ssam for (u = Uhead; u != NULL; ) { 197*13638Ssam if (strcmp(u->us_lname, name) == SAME) 198*13638Ssam /* found user name */ 199*13638Ssam return(u->us_callback); 200*13638Ssam u = u->unext; 201*13638Ssam } 202*13638Ssam 203*13638Ssam /* userid not found */ 204*13638Ssam return(0); 205*13638Ssam } 206*13638Ssam 207*13638Ssam 208*13638Ssam /*** 209*13638Ssam * chkperm(file, mopt) check write permission of file 210*13638Ssam * char *mopt; none NULL - create directories 211*13638Ssam * 212*13638Ssam * if mopt != NULL and permissions are ok, 213*13638Ssam * a side effect of this routine is to make 214*13638Ssam * directories up to the last part of the 215*13638Ssam * filename (if they do not exist). 216*13638Ssam * 217*13638Ssam * return 0 | FAIL 218*13638Ssam */ 219*13638Ssam 220*13638Ssam chkperm(file, mopt) 221*13638Ssam char *file, *mopt; 222*13638Ssam { 223*13638Ssam struct stat s; 224*13638Ssam int ret; 225*13638Ssam char dir[MAXFULLNAME]; 226*13638Ssam extern char *lastpart(); 227*13638Ssam 228*13638Ssam if (stat(subfile(file), &s) == 0) { 229*13638Ssam /* Forbid scribbling on a not-generally-writable file */ 230*13638Ssam /* rti!trt */ 231*13638Ssam if ((s.st_mode & ANYWRITE) == 0) 232*13638Ssam return(FAIL); 233*13638Ssam return(0); 234*13638Ssam } 235*13638Ssam 236*13638Ssam strcpy(dir, file); 237*13638Ssam *lastpart(dir) = '\0'; 238*13638Ssam if ((ret = stat(subfile(dir), &s)) == -1 239*13638Ssam && mopt == NULL) 240*13638Ssam return(FAIL); 241*13638Ssam 242*13638Ssam if (ret != -1) { 243*13638Ssam if ((s.st_mode & ANYWRITE) == 0) 244*13638Ssam return(FAIL); 245*13638Ssam else 246*13638Ssam return(0); 247*13638Ssam } 248*13638Ssam 249*13638Ssam /* make directories */ 250*13638Ssam return(mkdirs(file)); 251*13638Ssam } 252*13638Ssam 253*13638Ssam /* 254*13638Ssam * Check for sufficient privilege to request debugging. 255*13638Ssam * Suggested by seismo!stewart, John Stewart. 256*13638Ssam */ 257*13638Ssam chkdebug(uid) 258*13638Ssam int uid; 259*13638Ssam { 260*13638Ssam if (uid > PRIV_UIDS) { 261*13638Ssam fprintf(stderr, "Sorry, uid must be <= %d for debugging\n", 262*13638Ssam PRIV_UIDS); 263*13638Ssam cleanup(1); 264*13638Ssam exit(1); /* Just in case */ 265*13638Ssam } 266*13638Ssam } 267