|
|
1.1 root 1: /* /sccs/src/cmd/uucp/s.expfile.c
2: expfile.c 1.4 8/30/84 17:37:18
3: */
4: #include "uucp.h"
5: VERSION(@(#)expfile.c 1.4);
6:
7: /*
8: * expand file name expansion is based on first characters
9: * / -> fully qualified pathname. no
10: * processing necessary
11: * ~ -> prepended with login directory
12: * ~/ -> prepended with Pubdir
13: * default -> prepended with current directory
14: * file -> filename to expand
15: * returns:
16: * 0 -> ok
17: * FAIL -> no Wrkdir name available
18: */
19: expfile(file)
20: register char *file;
21: {
22: register char *fpart, *up;
23: int uid;
24: char user[NAMESIZE], save[MAXFULLNAME];
25:
26: strcpy(save, file);
27: if (*file == '/')
28: ;
29: else if (*file == '~') {
30: /* find / and copy user part */
31: for (fpart = save + 1, up = user; *fpart != '\0'
32: && *fpart != '/'; fpart++)
33: *up++ = *fpart;
34: *up = '\0';
35: if ((user[0]=='\0') || (gninfo(user, &uid, file) != 0)){
36: (void) strcpy(file, Pubdir);
37: }
38: (void) strcat(file, fpart);
39: }
40: else {
41: if (Wrkdir[0] == 0)
42: gwd(Wrkdir);
43: if (Wrkdir[0] == '\0')
44: return(FAIL);
45: (void) sprintf(file, "%s/%s", Wrkdir, save);
46: }
47:
48: if (canPath(file) != 0) { /* I don't think this will ever fail */
49: (void) strcpy(file, CORRUPTDIR);
50: return(FAIL);
51: }
52: else
53: return(0);
54: }
55:
56:
57: /*
58: * make all necessary directories
59: * name -> directory to make
60: * return:
61: * 0 -> success
62: * FAIL -> failure
63: */
64: mkdirs(name)
65: register char *name;
66: {
67: register char *p;
68: char dir[MAXFULLNAME];
69:
70: strcpy(dir, name);
71: if (*LASTCHAR(dir) != '/')
72: (void) strcat(dir, "/");
73: p = dir + 1;
74: while (1) {
75: if ((p = strchr(p, '/')) == NULL)
76: return(0);
77: *p = '\0';
78: DEBUG(4, "mkdir - %s\n", dir);
79: if (mkdirs2(dir, 0) == FAIL)
80: return (FAIL);
81: *p++ = '/';
82: }
83: }
84:
85:
86: #ifdef ATTSV
87: /*
88: * Make name a directory if it is not already a directory
89: * ATTSV handling of setuid is less than convenient ...
90: * return:
91: * 0 -> ok
92: * FAIL -> failed
93: */
94:
95: mkdirs2(name, mask)
96: register char *name;
97: register int mask;
98: {
99: int ret, pid, status;
100: char *tail, nmbuf[MAXFULLNAME], *parent;
101: struct stat statbuf;
102:
103: if (DIRECTORY(name))
104: return(0); /* directory exists */
105:
106: /* in ATTSV the parent directory has to be writeable by real uid */
107: (void) strcpy(nmbuf, name);
108:
109: /* get pathname of parent */
110: tail = nmbuf + strlen(nmbuf) - 1; /* last char in nmbuf */
111: while (*tail == '/' && tail > nmbuf) /* kill trailing slashes */
112: *tail-- = '\0';
113:
114: /* is parent "."? */
115: if ((tail = strrchr(nmbuf, '/')) != NULL) {
116: *tail = '\0';
117: parent = nmbuf;
118: } else
119: parent = ".";
120:
121: /* save mode of parent */
122: if (stat(parent, &statbuf) != 0) {
123: DEBUG(5, "CAN'T STAT PARENT DIRECTORY %s ", parent);
124: DEBUG(5, "errno %d\n", errno);
125: return(FAIL);
126: }
127:
128: /* if it's already 0xx7 we don't have to change it */
129: if ((statbuf.st_mode & 0777) != 0777) {
130: /* make parent writable by all (thus by real uid) */
131: if (chmod(parent, 0777) != 0) {
132: DEBUG(5, "CAN'T CHMOD PARENT DIRECTORY %s ", parent);
133: DEBUG(5, "errno %d\n", errno);
134: return(FAIL);
135: }
136: }
137:
138: switch (pid = fork()) {
139: case 0: /* child */
140: umask(0);
141: /* close stdout and stderr to fail quietly */
142: close(1);
143: close(2);
144: execl("/bin/mkdir", "mkdir", name, 0);
145: _exit(1);
146:
147: case -1: /* fork failed */
148: ASSERT(pid != -1, Ct_FORK, "mkdir", errno);
149:
150: default: /* parent */
151: break;
152: }
153: status = 1;
154: while ((ret = wait(&status)) != pid && ret > 0);
155:
156: if (status != 0) {
157: errent(Ct_CREATE, name, ret, sccsid, __FILE__, __LINE__);
158: return(FAIL);
159: }
160:
161:
162: if ((statbuf.st_mode & 0777) != 0777) {
163: /* restore mode of parent directory */
164: if (chmod(parent, statbuf.st_mode & 0777) != 0) {
165: errent(Ct_CHMOD, parent, errno, sccsid, __FILE__, __LINE__);
166: DEBUG(5, "CAN'T CHMOD PARENT %s\n", parent);
167: return(FAIL);
168: }
169: }
170:
171: if (Uid != 0) {
172: if (setuid(Uid) != 0) {
173: DEBUG(5, "CAN'T SETUID %d\n", Uid);
174: return(FAIL);
175: }
176: if ( chmod(name, (mask ^ 0777) & 0777) != 0) {
177: errent(Ct_CHMOD, name, errno, sccsid, __FILE__, __LINE__);
178: return(FAIL);
179: };
180: if (chown(name, UUCPUID, getgid()) != 0) {
181: DEBUG(5, "CHOWN FAILED %s ", name);
182: DEBUG(5, "errno %d\n", errno);
183: errent(Ct_CHOWN, name, errno, sccsid, __FILE__, __LINE__);
184: setuid(Euid);
185: return(FAIL);
186: }
187: setuid(Euid);
188: }
189: return(0);
190: }
191: #endif ATTSV
192:
193: #ifdef V7
194: mkdirs2(name, mask)
195: register char *name;
196: register int mask;
197: {
198: int ret;
199: int pid, rpid;
200: if (DIRECTORY(name))
201: return(0); /* directory exists */
202:
203: if ((pid = fork()) == 0) {
204: setuid(Euid); /* this makes it trivial in V7 */
205: umask(mask);
206: /* close stdout and stderr to fail quietly */
207: close(1);
208: close(2);
209: execl("/bin/mkdir", "mkdir", name, 0);
210: _exit(1);
211: }
212: ret = 1;
213: while ((rpid = wait(&ret)) > 0 && rpid != pid)
214: ;
215:
216: if (ret != 0) /* why should we abort if some remote tries */
217: return(FAIL); /* to make a garbage directory */
218:
219: return(0);
220: }
221: #endif V7
222:
223: /*
224: * expand file name and check return
225: * print error if it failed.
226: * file -> file name to check
227: * returns:
228: * 0 -> ok
229: * FAIL -> if expfile failed
230: */
231: ckexpf(file)
232: char *file;
233: {
234: if (expfile(file) == 0)
235: return(0);
236:
237: fprintf(stderr, "Illegal filename (%s).\n", file);
238: return(FAIL);
239: }
240:
241:
242: /*
243: * make canonical path out of path passed as argument.
244: *
245: * Eliminate redundant self-references like // or /./
246: * (A single terminal / will be preserved, however.)
247: * Dispose of references to .. in the path names.
248: * In relative path names, this means that .. or a/../..
249: * will be treated as an illegal reference.
250: * In full paths, .. is always allowed, with /.. treated as /
251: *
252: * returns:
253: * 0 -> path is now in canonical form
254: * FAIL -> relative path contained illegal .. reference
255: */
256:
257: int
258: canPath(path)
259: register char *path; /* path is modified in place */
260: {
261: register char *to, *fr;
262:
263: to = fr = path;
264: if (*fr == '/') *to++ = *fr++;
265: for (;;) {
266: /* skip past references to self and validate references to .. */
267: for (;;) {
268: if (*fr == '/') {
269: fr++;
270: continue;
271: }
272: if ((strncmp(fr, "./", 2) == SAME) || EQUALS(fr, ".")) {
273: fr++;
274: continue;
275: }
276: if ((strncmp(fr, "../", 3) == SAME) || EQUALS(fr, "..")) {
277: fr += 2;
278: /* /.. is / */
279: if (((to - 1) == path) && (*path == '/')) continue;
280: /* error if no previous component */
281: if (to <= path) return (FAIL);
282: /* back past previous component */
283: while ((--to > path) && (to[-1] != '/'));
284: continue;
285: }
286: break;
287: }
288: /*
289: * What follows is a legitimate component,
290: * terminated by a null or a /
291: */
292: if (*fr == '\0') break;
293: while ((*to++ = *fr) && (*fr++ != '/'));
294: }
295: /* null path is . */
296: if (to == path) *to++ = '.';
297: *to = '\0';
298: return (0);
299: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.