Commit | Line | Data |
---|---|---|
e4b163b1 AM |
1 | /* prsvunix.c */ |
2 | ||
3 | /* This file contains the UNIX-specific parts of the "elvprsv" program. */ | |
4 | ||
5 | #if OSK | |
6 | #define ELVPRSV | |
7 | #include "osk.c" | |
8 | #else | |
9 | #include <sys/stat.h> | |
10 | #include <pwd.h> | |
11 | #endif | |
12 | #ifndef __STDC__ | |
13 | /* some older systems don't declare this in pwd.h, I guess. */ | |
14 | extern struct passwd *getpwuid(); | |
15 | #endif | |
16 | ||
17 | #if ANY_UNIX /* { */ | |
18 | /* Since elvprsv runs as SUID-root, we need a *secure* version of popen() */ | |
19 | #define popen safe_popen | |
20 | #define pclose safe_pclose | |
21 | ||
22 | /* This function is similar to the standard popen() function, except for... | |
23 | * 1) It doesn't use the shell, for security reasons. | |
24 | * 2) Shell services are not supported, including quoting. | |
25 | * 3) The mode can only be "w". "r" is not supported. | |
26 | * 4) No more than 9 arguments can be given, including the command. | |
27 | */ | |
28 | /*ARGSUSED*/ | |
29 | static FILE *safe_popen(cmd, mode) | |
30 | char *cmd; /* the filename of the program to be run */ | |
31 | char *mode; /* "w", ignored */ | |
32 | { | |
33 | char path[100];/* full pathname of argv[0] */ | |
34 | char *argv[10];/* the arguments */ | |
35 | int r0w1[2];/* the pipe fd's */ | |
36 | int i; | |
37 | FILE *fp; | |
38 | ||
39 | /* parse the arguments */ | |
40 | for (i = 0; i < 9 && *cmd; i++) | |
41 | { | |
42 | /* remember where this arg starts */ | |
43 | argv[i] = cmd; | |
44 | ||
45 | /* move to the end of the argument */ | |
46 | do | |
47 | { | |
48 | cmd++; | |
49 | } while (*cmd && *cmd != ' '); | |
50 | ||
51 | /* then mark end of arg & skip to next */ | |
52 | while (*cmd && *cmd == ' ') | |
53 | { | |
54 | *cmd++ = '\0'; | |
55 | } | |
56 | printf("argv[%d]=\"%s\"\n", i, argv[i]); | |
57 | } | |
58 | argv[i] = (char *)0; | |
59 | ||
60 | /* make the pipe */ | |
61 | if (pipe(r0w1) < 0) | |
62 | { | |
63 | perror("pipe()"); | |
64 | return (FILE *)0; /* pipe failed */ | |
65 | } | |
66 | ||
67 | switch (fork()) | |
68 | { | |
69 | case -1: /* error */ | |
70 | perror("fork()"); | |
71 | return (FILE *)0; | |
72 | ||
73 | case 0: /* child */ | |
74 | /* close the "write" end of the pipe */ | |
75 | close(r0w1[1]); | |
76 | ||
77 | /* redirect stdin to come from the "read" end of the pipe */ | |
78 | close(0); | |
79 | dup(r0w1[0]); | |
80 | close(r0w1[0]); | |
81 | ||
82 | /* exec the shell to run the command */ | |
83 | if (*argv[0] != '/') | |
84 | { | |
85 | /* no path, try "/bin/argv[0]" */ | |
86 | strcpy(path, "/bin/"); | |
87 | strcat(path, argv[0]); | |
88 | execv(path, argv); | |
89 | perror(path); | |
90 | ||
91 | /* if that failed, then try "/usr/bin/argv[0]" */ | |
92 | strcpy(path, "/usr/bin/"); | |
93 | strcat(path, argv[0]); | |
94 | execv(path, argv); | |
95 | perror(path); | |
96 | } | |
97 | else | |
98 | { | |
99 | /* full pathname given, so use it */ | |
100 | execv(argv[0], argv); | |
101 | perror(argv[0]); | |
102 | } | |
103 | ||
104 | /* if we get here, exec failed */ | |
105 | exit(1); | |
106 | ||
107 | default: /* parent */ | |
108 | /* close the "read" end of the pipe */ | |
109 | close(r0w1[0]); | |
110 | ||
111 | /* convert the "write" fd into a (FILE *) */ | |
112 | fp = fdopen(r0w1[1], "w"); | |
113 | return fp; | |
114 | } | |
115 | /*NOTREACHED*/ | |
116 | } | |
117 | ||
118 | ||
119 | /* This function closes the pipe opened by popen(), and returns 0 for success */ | |
120 | static int safe_pclose(fp) | |
121 | FILE *fp; /* value returned by popen() */ | |
122 | { | |
123 | int status; | |
124 | ||
125 | /* close the file, and return the defunct child's exit status */ | |
126 | fclose(fp); | |
127 | wait(&status); | |
128 | return status; | |
129 | } | |
130 | #endif /* } ANY UNIX */ | |
131 | ||
132 | ||
133 | /* This variable is used to add extra error messages for mail sent to root */ | |
134 | char *ps; | |
135 | ||
136 | /* This function returns the login name of the owner of a file */ | |
137 | char *ownername(filename) | |
138 | char *filename; /* name of a file */ | |
139 | { | |
140 | struct stat st; | |
141 | struct passwd *pw; | |
142 | ||
143 | /* stat the file, to get its uid */ | |
144 | if (stat(filename, &st) < 0) | |
145 | { | |
146 | ps = "stat() failed"; | |
147 | return "root"; | |
148 | } | |
149 | ||
150 | /* get the /etc/passwd entry for that user */ | |
151 | pw = getpwuid(st.st_uid); | |
152 | if (!pw) | |
153 | { | |
154 | ps = "uid not found in password file"; | |
155 | return "root"; | |
156 | } | |
157 | ||
158 | /* return the user's name */ | |
159 | return pw->pw_name; | |
160 | } | |
161 | ||
162 | ||
163 | /* This function sends a mail message to a given user, saying that a file | |
164 | * has been preserved. | |
165 | */ | |
166 | void mail(user, file, when) | |
167 | char *user; /* name of user who should receive the mail */ | |
168 | char *file; /* name of original text file that was preserved */ | |
169 | char *when; /* description of why the file was preserved */ | |
170 | { | |
171 | char cmd[80];/* buffer used for constructing a "mail" command */ | |
172 | FILE *m; /* stream used for giving text to the "mail" program */ | |
173 | char *base; /* basename of the file */ | |
174 | ||
175 | /* separate the directory name from the basename. */ | |
176 | for (base = file + strlen(file); --base > file && *base != SLASH; ) | |
177 | { | |
178 | } | |
179 | if (*base == SLASH) | |
180 | { | |
181 | *base++ = '\0'; | |
182 | } | |
183 | ||
184 | /* for anonymous buffers, pretend the name was "foo" */ | |
185 | if (!strcmp(base, "*")) | |
186 | { | |
187 | base = "foo"; | |
188 | } | |
189 | ||
190 | /* open a pipe to the "mail" program */ | |
191 | #if OSK | |
192 | sprintf(cmd, "mail \"-s=%s preserved!\" %s", base, user); | |
193 | #else /* ANY_UNIX */ | |
194 | sprintf(cmd, "mail -s Graceland %s", user); | |
195 | #endif | |
196 | m = popen(cmd, "w"); | |
197 | if (!m) | |
198 | { | |
199 | perror(cmd); | |
200 | /* Can't send mail! Hope the user figures it out. */ | |
201 | return; | |
202 | } | |
203 | ||
204 | /* Tell the user that the file was preserved */ | |
205 | fprintf(m, "A version of your file \"%s%c%s\"\n", file, SLASH, base); | |
206 | fprintf(m, "was preserved when %s.\n", when); | |
207 | fprintf(m, "To recover this file, do the following:\n"); | |
208 | fprintf(m, "\n"); | |
209 | #if OSK | |
210 | fprintf(m, " chd %s\n", file); | |
211 | #else /* ANY_UNIX */ | |
212 | fprintf(m, " cd %s\n", file); | |
213 | #endif | |
214 | fprintf(m, " elvisrecover %s\n", base); | |
215 | fprintf(m, "\n"); | |
216 | fprintf(m, "With fond wishes for a speedy recovery,\n"); | |
217 | fprintf(m, " Elvis\n"); | |
218 | if (ps) | |
219 | { | |
220 | fprintf(m, "\nP.S. %s\n", ps); | |
221 | ps = (char *)0; | |
222 | } | |
223 | ||
224 | /* close the stream */ | |
225 | pclose(m); | |
226 | } |