bug fixes and changes from Rick Adams
[unix-history] / usr / src / usr.bin / uucp / uusend / uusend.c
CommitLineData
877b2bc4 1#ifndef lint
46b15d8a 2static char sccsid[] = "@(#)uusend.c 5.2 (Berkeley) %G%";
877b2bc4
SL
3#endif
4
5/*
6 * uusend: primitive operation to allow uucp like copy of binary files
7 * but handle indirection over systems.
8 *
9 * usage: uusend [-r] [-m ooo] localfile sysname1!sysname2!...!destfile
10 * uusend [-r] [-m ooo] - sysname1!sysname2!...!destfile
11 *
12 * Author: Mark Horton, May 1980.
13 *
14 * "-r" switch added. Has same effect as "-r" in uux. 11/82 CCW
15 *
16 * Error recovery (a la uucp) added & ifdefs for ruusend (as in rmail).
17 * Checks for illegal access to /usr/lib/uucp.
18 * February 1983 Christopher Woodbury
19 * Fixed mode set[ug]id loophole. 4/8/83 CCW
20 *
21 * Add '-f' to make uusend syntax more similar to UUCP. "destname"
22 * can now be a directory. June 1983 CCW
23 */
24
25#include <stdio.h>
26#include <pwd.h>
27#include <sys/types.h>
28#include <sys/stat.h>
29
46b15d8a
RC
30/*
31 * define RECOVER to permit requests like 'uusend file sys1!sys2!~uucp'
32 * (abbreviation for 'uusend file sys1!sys2!~uucp/file').
33 * define DEBUG to keep log of uusend uusage.
34 * define RUUSEND if neighboring sites permit 'ruusend',
35 * which they certainly should to avoid security holes
36 */
877b2bc4 37#define RECOVER
46b15d8a 38/*#define DEBUG "/usr/spool/uucp/uusend.log"/**/
877b2bc4
SL
39
40FILE *in, *out;
41FILE *dout;
42
46b15d8a
RC
43extern FILE *popen();
44extern char *index(), *strcpy(), *strcat(), *ctime();
877b2bc4
SL
45
46#ifdef RUUSEND
47int rsend;
46b15d8a 48#endif RUUSEND
877b2bc4
SL
49int mode = -1; /* mode to chmod new file to */
50char *nextsys; /* next system in the chain */
51char dnbuf[200]; /* buffer for result of ~user/file */
52char cmdbuf[256]; /* buffer to build uux command in */
53char *rflg = ""; /* default value of rflg ccw -- 1 Nov '82 */
54
55struct passwd *user; /* entry in /etc/passwd for ~user */
56struct passwd *getpwnam();
57struct stat stbuf;
58
59char *excl; /* location of first ! in destname */
60char *sl; /* location of first / in destname */
61char *sourcename; /* argv[1] */
62char *destname; /* argv[2] */
63char *UULIB = "/usr/lib/uucp"; /* UUCP lib directory */
64
65#ifdef RECOVER
66char *UUPUB = "/usr/spool/uucppublic/"; /* public UUCP directory */
67char *filename; /* file name from end of destname */
68char *getfname(); /* routine to get filename from destname */
69int fflg;
70char f[100]; /* name of default output file */
46b15d8a 71#else !RECOVER
877b2bc4 72char *f = ""; /* so we waste a little space */
46b15d8a 73#endif !RECOVER
877b2bc4
SL
74
75main(argc, argv)
76int argc;
77char **argv;
78{
79 register int c;
46b15d8a
RC
80 long count;
81 extern char **environ;
877b2bc4
SL
82
83#ifdef DEBUG
84 long t;
46b15d8a 85 umask(022);
877b2bc4
SL
86 dout = fopen(DEBUG, "a");
87 if (dout == NULL) {
88 printf("Cannot append to %s\n", DEBUG);
89 exit(1);
90 }
91 freopen(DEBUG, "a", stdout);
877b2bc4
SL
92 fprintf(dout, "\nuusend run: ");
93 for (c=0; c<argc; c++)
94 fprintf(dout, "%s ", argv[c]);
95 time(&t);
96 fprintf(dout, "%s", ctime(&t));
46b15d8a 97#endif DEBUG
877b2bc4
SL
98
99#ifdef RUUSEND
100 if(argv[0][0] == 'r')
101 rsend++;
46b15d8a 102#endif RUUSEND
877b2bc4
SL
103 while (argc > 1 && argv[1][0] == '-' && argv[1][1]) {
104 switch(argv[1][1]) {
105 case 'm':
106 sscanf(argv[2], "%o", &mode);
107 mode &= 0777; /* fix set[ug]id loophole */
108 argc--; argv++;
109 break;
110 case 'r': /* -r flag for uux */
111 rflg = "-r ";
112 break;
113#ifdef RECOVER
114 case 'f':
115 fflg++;
116 strcpy(f, argv[1]);
117 break;
46b15d8a 118#endif RECOVER
877b2bc4
SL
119 default:
120 fprintf(stderr, "Bad flag: %s\n", argv[1]);
121 break;
122 }
123 argc--; argv++;
124 }
125
126 if (argc != 3) {
127 fprintf(stderr, "Usage: uusend [-m ooo] [-r] -/file sys!sys!..!rfile\n");
128 exit(1);
129 }
130
131 sourcename = argv[1];
132 destname = argv[2];
133
134 if (sourcename[0] == '-')
135 in = stdin;
136 else {
137#ifdef RUUSEND
138 if (rsend) {
139 fprintf(stderr, "illegal input\n");
140 exit(2);
141 }
46b15d8a 142#endif RUUSEND
877b2bc4
SL
143 in = fopen(sourcename, "r");
144 if (in == NULL) {
145 perror(argv[1]);
146 exit(2);
147 }
148 if (!fflg || f[2] == '\0') {
149 strcpy(f, "-f");
150 strcat(f, getfname(sourcename));
151 fflg++;
152 }
153 }
154
155 excl = index(destname, '!');
156 if (excl) {
157 /*
158 * destname is on a remote system.
159 */
160 nextsys = destname;
161 *excl++ = 0;
162 destname = excl;
163 if (mode < 0) {
164 fstat(fileno(in), &stbuf);
165 mode = stbuf.st_mode & 0777;
166 }
167#ifdef RUUSEND
46b15d8a
RC
168 sprintf(cmdbuf,"uux -gn -z %s- \"%s!ruusend %s -m %o - (%s)\"",
169#else !RUUSEND
170 sprintf(cmdbuf, "uux -gn -z %s- \"%s!uusend %s -m %o - (%s)\"",
171#endif !RUUSEND
877b2bc4
SL
172 rflg, nextsys, f, mode, destname);
173#ifdef DEBUG
174 fprintf(dout, "remote: nextsys='%s', destname='%s', cmd='%s'\n", nextsys, destname, cmdbuf);
46b15d8a 175#endif DEBUG
877b2bc4
SL
176 out = popen(cmdbuf, "w");
177 } else {
178 /*
179 * destname is local.
180 */
181 if (destname[0] == '~') {
182#ifdef DEBUG
183 fprintf(dout, "before ~: '%s'\n", destname);
184fflush(dout);
46b15d8a 185#endif DEBUG
877b2bc4
SL
186 sl = index(destname, '/');
187#ifdef RECOVER
188 if (sl == NULL && !fflg) {
189 fprintf(stderr, "Illegal ~user\n");
190 exit(3);
191 }
192 for (sl = destname; *sl != '\0'; sl++)
193 ; /* boy, is this a hack! */
46b15d8a 194#else !RECOVER
877b2bc4
SL
195 if (sl == NULL) {
196 fprintf(stderr, "Illegal ~user\n");
197 exit(3);
198 }
199 *sl++ = 0;
46b15d8a 200#endif !RECOVER
877b2bc4
SL
201 user = getpwnam(destname+1);
202 if (user == NULL) {
203 fprintf(stderr, "No such user as %s\n",
204 destname);
205#ifdef RECOVER
206 if ((filename =getfname(sl)) == NULL &&
207 !fflg)
208 exit(4);
209 strcpy(dnbuf, UUPUB);
210 if (fflg)
211 strcat(dnbuf, &f[2]);
212 else
213 strcat(dnbuf, filename);
214 }
215 else {
216 strcpy(dnbuf, user->pw_dir);
217 strcat(dnbuf, "/");
218 strcat(dnbuf, sl);
219 }
46b15d8a 220#else !RECOVER
877b2bc4
SL
221 exit(4);
222 }
223 strcpy(dnbuf, user->pw_dir);
224 strcat(dnbuf, "/");
225 strcat(dnbuf, sl);
46b15d8a 226#endif !RECOVER
877b2bc4
SL
227 destname = dnbuf;
228 }
229#ifdef RECOVER
230 else
231 destname = strcpy(dnbuf, destname);
46b15d8a 232#endif !RECOVER
877b2bc4
SL
233 if(strncmp(UULIB, destname, strlen(UULIB)) == 0) {
234 fprintf(stderr, "illegal file: %s", destname);
235 exit(4);
236 }
237#ifdef RECOVER
238 if (stat(destname, &stbuf) == 0 &&
239 (stbuf.st_mode & S_IFMT) == S_IFDIR &&
240 fflg) {
46b15d8a
RC
241 strcat(destname, "/");
242 strcat(destname, &f[2]);
877b2bc4 243 }
46b15d8a 244#endif RECOVER
877b2bc4
SL
245 out = fopen(destname, "w");
246#ifdef DEBUG
247 fprintf(dout, "local, file='%s'\n", destname);
46b15d8a 248#endif DEBUG
877b2bc4
SL
249 if (out == NULL) {
250 perror(destname);
251#ifdef RECOVER
252 if (strncmp(destname,UUPUB,strlen(UUPUB)) == 0)
253 exit(5); /* forget it! */
254 filename = getfname(destname);
255 if (destname == dnbuf) /* cmdbuf is scratch */
256 filename = strcpy(cmdbuf, filename);
257 destname = strcpy(dnbuf, UUPUB);
258 if (user != NULL) {
259 strcat(destname, user->pw_name);
260 if (stat(destname, &stbuf) == -1) {
46b15d8a 261 mkdir(destname, 0777);
877b2bc4
SL
262 }
263 strcat(destname, "/");
264 }
877b2bc4
SL
265 if (fflg)
266 strcat(destname, &f[2]);
267 else
268 strcat(destname, filename);
877b2bc4
SL
269 if ((out = fopen(destname, "w")) == NULL)
270 exit(5); /* all for naught! */
46b15d8a 271#else !RECOVER
877b2bc4 272 exit(5);
46b15d8a 273#endif !RECOVER
877b2bc4
SL
274 }
275 if (mode > 0)
276 chmod(destname, mode); /* don't bother to check it */
277 }
278
279 /*
280 * Now, in any case, copy from in to out.
281 */
282
46b15d8a 283 count = 0;
877b2bc4
SL
284 while ((c=getc(in)) != EOF) {
285 putc(c, out);
286 count++;
287 }
288#ifdef DEBUG
289 fprintf(dout, "count %ld bytes\n", count);
290 fclose(dout);
46b15d8a
RC
291#endif DEBUG
292
877b2bc4
SL
293 fclose(in);
294 fclose(out); /* really should pclose in that case */
295 exit(0);
296}
297
298/*
299 * Return the ptr in sp at which the character c appears;
300 * NULL if not found. Included so I don't have to fight the
301 * index/strchr battle.
302 */
303
304#define NULL 0
305
306char *
307index(sp, c)
308register char *sp, c;
309{
310 do {
311 if (*sp == c)
312 return(sp);
313 } while (*sp++);
314 return(NULL);
315}
316
317#ifdef RECOVER
318char *
319getfname(p)
320register char *p;
321{
322 register char *s;
323 s = p;
324 while (*p != '\0')
325 p++;
326 if (p == s)
327 return (NULL);
328 for (;p != s; p--)
329 if (*p == '/') {
330 p++;
331 break;
332 }
333 return (p);
334}
335
46b15d8a
RC
336#ifndef BSD4_2
337makedir(dirname, mode)
877b2bc4 338char *dirname;
46b15d8a 339int mode;
877b2bc4
SL
340{
341 register int pid;
342 int retcode, status;
343 switch ((pid = fork())) {
344 case -1: /* error */
345 return (-1);
877b2bc4
SL
346 case 0: /* child */
347 umask(0);
46b15d8a 348 execl("/bin/mkdir", "mkdir", dirname, (char *)0);
877b2bc4 349 exit(1);
46b15d8a 350 /* NOTREACHED */
877b2bc4
SL
351 default: /* parent */
352 while ((retcode=wait(&status)) != pid && retcode != -1)
353 ;
354 if (retcode == -1)
46b15d8a
RC
355 return -1;
356 else {
357 chmod(dirname, mode);
358 return status;
359 }
877b2bc4 360 }
46b15d8a 361 /* NOTREACHED */
877b2bc4 362}
46b15d8a
RC
363#endif !BSD4_2
364#endif RECOVER