1 | /* |
---|
2 | * This file is part of the OLC On-Line Consulting System. |
---|
3 | * It contains functions for handling the daemon's I/O. |
---|
4 | * |
---|
5 | * Win Treese |
---|
6 | * Dan Morgan |
---|
7 | * Bill Saphir |
---|
8 | * MIT Project Athena |
---|
9 | * |
---|
10 | * Ken Raeburn |
---|
11 | * MIT Information Systems |
---|
12 | * |
---|
13 | * Tom Coppeto |
---|
14 | * MIT Project Athena |
---|
15 | * |
---|
16 | * Copyright (c) 1988 by the Massachusetts Institute of Technology |
---|
17 | * |
---|
18 | * $Source: /afs/dev.mit.edu/source/repository/athena/bin/olc/server/olcd/notify.c,v $ |
---|
19 | * $Author: tjcoppet $ |
---|
20 | */ |
---|
21 | |
---|
22 | #ifndef lint |
---|
23 | static char rcsid[]="$Header: /afs/dev.mit.edu/source/repository/athena/bin/olc/server/olcd/notify.c,v 1.3 1989-08-22 14:03:07 tjcoppet Exp $"; |
---|
24 | #endif |
---|
25 | |
---|
26 | |
---|
27 | #include <olc/olc.h> |
---|
28 | #include <olcd.h> |
---|
29 | |
---|
30 | #ifdef ZEPHYR |
---|
31 | #include <zephyr/zephyr.h> /* Zephyr defs. */ |
---|
32 | #endif ZEPHYR |
---|
33 | |
---|
34 | #include <sys/socket.h> /* IPC socket defs. */ |
---|
35 | #include <sys/file.h> /* File handling defs. */ |
---|
36 | #include <sys/stat.h> /* File status defs. */ |
---|
37 | #include <sys/wait.h> /* */ |
---|
38 | #include <netdb.h> /* Net database defs. */ |
---|
39 | #include <pwd.h> /* Directory defs. */ |
---|
40 | #include <signal.h> /* System signal definitions. */ |
---|
41 | #include <sgtty.h> /* Terminal param. definitions. */ |
---|
42 | #include <setjmp.h> |
---|
43 | |
---|
44 | |
---|
45 | /* External Variables. */ |
---|
46 | |
---|
47 | extern char DaemonHost[]; /* Name of daemon's machine. */ |
---|
48 | |
---|
49 | int notice_timeout(); |
---|
50 | static jmp_buf env; |
---|
51 | |
---|
52 | /* |
---|
53 | * Function: write_message() uses the program "write" to send a message |
---|
54 | * from one person to another within the OLC system. |
---|
55 | * Arguments: touser: Username of person receiving the message. |
---|
56 | * tomachine: Name of machine he is using. |
---|
57 | * fromuser: Username of person sending the message. |
---|
58 | * frommachine: Name of machine she is using. |
---|
59 | * message: Ptr. to buffer containing message. |
---|
60 | * Returns: SUCCESS or ERROR. |
---|
61 | * Notes: |
---|
62 | * First try using zwrite_message() for Zephyr users; if that fails, |
---|
63 | * use the standard Unix write code. |
---|
64 | * This code is essentially the same as that in write.c for the |
---|
65 | * program 'write'. |
---|
66 | * |
---|
67 | */ |
---|
68 | |
---|
69 | static int write_port = 0; |
---|
70 | |
---|
71 | ERRCODE |
---|
72 | write_message(touser, tomachine, fromuser, frommachine, message) |
---|
73 | char *touser, *tomachine, *fromuser, *frommachine, *message; |
---|
74 | { |
---|
75 | FILE *tf = NULL; /* Temporary file. */ |
---|
76 | int fds; /* Socket descriptor. */ |
---|
77 | char buf[BUFSIZE]; /* Message buffer. */ |
---|
78 | char error[ERRSIZE]; /* Error message. */ |
---|
79 | struct hostent *host; /* Host entry for receiver. */ |
---|
80 | struct sockaddr_in sin; /* Socket address. */ |
---|
81 | int flag = 0; |
---|
82 | |
---|
83 | if (touser == (char *)NULL) /* User sanity check. */ |
---|
84 | return(ERROR); |
---|
85 | |
---|
86 | #ifdef ZEPHYR |
---|
87 | /* First try using Zephyr write. If return status is anything |
---|
88 | * but SUCCESS, try again using Unix write. |
---|
89 | */ |
---|
90 | if (zwrite_message(touser, message) == SUCCESS) |
---|
91 | return(SUCCESS); |
---|
92 | #endif ZEPHYR |
---|
93 | |
---|
94 | if (write_port == 0) { |
---|
95 | struct servent *service; |
---|
96 | service = getservbyname("write", "tcp"); |
---|
97 | if (!service) { |
---|
98 | log_error("write_message: Can't find 'write' service"); |
---|
99 | return(ERROR); |
---|
100 | } |
---|
101 | write_port = service->s_port; |
---|
102 | } |
---|
103 | |
---|
104 | host = gethostbyname(tomachine); |
---|
105 | if (host == (struct hostent *)NULL) { |
---|
106 | (void) sprintf(error, |
---|
107 | "Can't resolve name of host '%s'", tomachine); |
---|
108 | log_error(error); |
---|
109 | return(ERROR); |
---|
110 | } |
---|
111 | sin.sin_family = host->h_addrtype; |
---|
112 | bcopy(host->h_addr, (char *) &sin.sin_addr, host->h_length); |
---|
113 | sin.sin_port = write_port; |
---|
114 | fds = socket(host->h_addrtype, SOCK_STREAM, 0); |
---|
115 | if (fds < 0) { |
---|
116 | perror("socket"); |
---|
117 | exit(1); |
---|
118 | } |
---|
119 | |
---|
120 | |
---|
121 | signal(SIGALRM, notice_timeout); |
---|
122 | alarm(OLCD_TIMEOUT); |
---|
123 | if(setjmp(env) != 0) { |
---|
124 | sprintf(error, "Unable to contact writed on %s", tomachine); |
---|
125 | log_error(error); |
---|
126 | if(tf!=NULL) |
---|
127 | fclose(tf); |
---|
128 | close(fds); |
---|
129 | alarm(0); |
---|
130 | return(ERROR); |
---|
131 | } |
---|
132 | |
---|
133 | |
---|
134 | if (connect(fds, &sin, sizeof (sin)) < 0) { |
---|
135 | alarm(0); |
---|
136 | (void) close(fds); |
---|
137 | return(MACHINE_DOWN); |
---|
138 | } |
---|
139 | (void) write(fds, fromuser, strlen(fromuser)); |
---|
140 | (void) write(fds, "@", 1); |
---|
141 | (void) write(fds, frommachine, strlen(frommachine)); |
---|
142 | (void) write(fds, " ", 1); |
---|
143 | (void) write(fds, touser, strlen(touser)); |
---|
144 | (void) write(fds, "\r\n", 2); |
---|
145 | tf = fdopen(fds, "r"); |
---|
146 | flag++; |
---|
147 | while (1) { |
---|
148 | if (fgets(buf, sizeof(buf), tf) == (char *)NULL) { |
---|
149 | (void) fclose(tf); |
---|
150 | (void) close(fds); |
---|
151 | alarm(0); |
---|
152 | return(LOGGED_OUT); |
---|
153 | } |
---|
154 | if (buf[0] == '\n') |
---|
155 | break; |
---|
156 | (void) write(1, buf, strlen(buf)); |
---|
157 | } |
---|
158 | (void) write(fds, message, strlen(message)); |
---|
159 | (void) write(fds, "\r\n", 2); |
---|
160 | (void) fclose(tf); |
---|
161 | (void) close(fds); |
---|
162 | alarm(0); |
---|
163 | return(SUCCESS); |
---|
164 | } |
---|
165 | |
---|
166 | |
---|
167 | int |
---|
168 | notice_timeout(a) |
---|
169 | int a; |
---|
170 | { |
---|
171 | longjmp(env, 1); |
---|
172 | } |
---|
173 | |
---|
174 | |
---|
175 | /* |
---|
176 | * Function: write_message_to_user() sends a message from the |
---|
177 | * daemon to a user using "write". |
---|
178 | * Arguments: user: Ptr. to user structure. |
---|
179 | * message: Ptr. to buffer containing the message. |
---|
180 | * flags: Specifies special actions. |
---|
181 | * Returns: SUCCESS or ERROR. |
---|
182 | * Notes: |
---|
183 | * First, try to write a message to the user. If it does not |
---|
184 | * succeed, notify the consultant. |
---|
185 | */ |
---|
186 | |
---|
187 | |
---|
188 | ERRCODE |
---|
189 | write_message_to_user(k, message, flags) |
---|
190 | KNUCKLE *k; |
---|
191 | char *message; |
---|
192 | int flags; |
---|
193 | { |
---|
194 | int result; /* Result of writing the message. */ |
---|
195 | char msgbuf[BUFSIZE]; /* Message buffer. */ |
---|
196 | int status; |
---|
197 | |
---|
198 | if (k == (KNUCKLE *) NULL) |
---|
199 | return(ERROR); |
---|
200 | |
---|
201 | if(k->user->no_knuckles > 1) |
---|
202 | { |
---|
203 | sprintf(msgbuf,"To: %s %s@%s (%d)\n",k->title,k->user->username, |
---|
204 | k->user->realm,k->instance); |
---|
205 | strcat(msgbuf,message); |
---|
206 | result = write_message(k->user->username, k->user->machine, |
---|
207 | "OLC-Daemon", DaemonHost, msgbuf); |
---|
208 | } |
---|
209 | else |
---|
210 | result = write_message(k->user->username, k->user->machine, |
---|
211 | "OLC-Daemon", DaemonHost, message); |
---|
212 | |
---|
213 | switch(result) |
---|
214 | { |
---|
215 | case ERROR: |
---|
216 | set_status(k->user, UNKNOWN_STATUS); |
---|
217 | (void) sprintf(msgbuf,"Unable to contact %s %s. Cause unknown", |
---|
218 | k->title, k->user->username); |
---|
219 | if(!(flags & NO_RESPOND)) |
---|
220 | (void) write_message_to_user(k->connected, msgbuf, NO_RESPOND); |
---|
221 | log_daemon(k, msgbuf); |
---|
222 | status = ERROR; |
---|
223 | break; |
---|
224 | |
---|
225 | case MACHINE_DOWN: |
---|
226 | set_status(k->user, UNKNOWN_STATUS); |
---|
227 | (void) sprintf(msgbuf,"Unable to contact %s %s. Host machine down.", |
---|
228 | k->title, k->user->username); |
---|
229 | if(!(flags & NO_RESPOND)) |
---|
230 | (void) write_message_to_user(k->connected, msgbuf, NO_RESPOND); |
---|
231 | log_daemon(k, msgbuf); |
---|
232 | status = ERROR; |
---|
233 | break; |
---|
234 | |
---|
235 | case LOGGED_OUT: |
---|
236 | set_status(k->user, LOGGED_OUT); |
---|
237 | (void) sprintf(msgbuf,"Unable to contact %s %s. User logged out.", |
---|
238 | k->title, k->user->username); |
---|
239 | if(!(flags & NO_RESPOND)) |
---|
240 | (void) write_message_to_user(k->connected, msgbuf, NO_RESPOND); |
---|
241 | log_daemon(k, msgbuf); |
---|
242 | status = ERROR; |
---|
243 | break; |
---|
244 | |
---|
245 | default: |
---|
246 | set_status(k->user,ACTIVE); |
---|
247 | status = SUCCESS; |
---|
248 | break; |
---|
249 | } |
---|
250 | return(status); |
---|
251 | } |
---|
252 | |
---|
253 | #define FUDGEFACTOR 20 |
---|
254 | #define MESSAGE_CLASS "MESSAGE" |
---|
255 | #define PERSONAL_INSTANCE "PERSONAL" |
---|
256 | #define OLC_INSTANCE "OLC" |
---|
257 | #ifdef TEST |
---|
258 | #define OLC_CLASS "OLCTEST" |
---|
259 | #else TEST |
---|
260 | #define OLC_CLASS "OLC_FOOL" |
---|
261 | #endif TEST |
---|
262 | |
---|
263 | ERRCODE olc_broadcast_message(instance,message, code) |
---|
264 | char *instance, *message, *code; |
---|
265 | { |
---|
266 | #ifdef ZEPHYR |
---|
267 | if(zsend_message(OLC_CLASS,instance,code,"",message,0) == ERROR) |
---|
268 | return(ERROR); |
---|
269 | #endif ZEPHYR |
---|
270 | |
---|
271 | return(SUCCESS); |
---|
272 | } |
---|
273 | |
---|
274 | #ifdef ZEPHYR |
---|
275 | |
---|
276 | /* |
---|
277 | * Function: zwrite_message(username, message) writes a message to the |
---|
278 | * specified user. |
---|
279 | * Arguments: username: Username of intended recipient. |
---|
280 | * message: Message to send. |
---|
281 | * Returns: SUCCESS if message sent successfully, else ERROR. |
---|
282 | * |
---|
283 | * Inspired greatly by Robert French's zwrite.c (i.e. somewhat swiped). |
---|
284 | * |
---|
285 | */ |
---|
286 | |
---|
287 | |
---|
288 | ERRCODE |
---|
289 | zwrite_message(username, message) |
---|
290 | char *username; |
---|
291 | char *message; |
---|
292 | { |
---|
293 | char error[ERRSIZE]; |
---|
294 | |
---|
295 | /* Sanity check the username. */ |
---|
296 | if (username == NULL) |
---|
297 | { |
---|
298 | (void) sprintf(error, "zwrite_message: null username"); |
---|
299 | log_error(error); |
---|
300 | return(ERROR); |
---|
301 | } |
---|
302 | if (strlen(username) == 0) |
---|
303 | { |
---|
304 | (void) sprintf(error, "zwrite_message: zero length username"); |
---|
305 | log_error(error); |
---|
306 | return(ERROR); |
---|
307 | } |
---|
308 | |
---|
309 | if(zsend_message(MESSAGE_CLASS,PERSONAL_INSTANCE,"olc hello",username,message,0) |
---|
310 | == ERROR) |
---|
311 | return(ERROR); |
---|
312 | |
---|
313 | return(SUCCESS); |
---|
314 | } |
---|
315 | |
---|
316 | |
---|
317 | ERRCODE |
---|
318 | zsend_message(class,instance,opcode,username,message, flags) |
---|
319 | char *class,*instance,*opcode,*username,*message; |
---|
320 | int flags; |
---|
321 | { |
---|
322 | ZNotice_t notice; /* Zephyr notice */ |
---|
323 | int ret; /* return value, length */ |
---|
324 | char error[ERRSIZE]; |
---|
325 | char buf[BUFSIZ]; |
---|
326 | char *signature = "From: OLC Service \n"; |
---|
327 | |
---|
328 | #ifdef lint |
---|
329 | flags = flags; |
---|
330 | opcode = opcode; |
---|
331 | #endif lint; |
---|
332 | |
---|
333 | if ((ret = ZInitialize()) != ZERR_NONE) |
---|
334 | { |
---|
335 | (void) sprintf(error, "zwrite_message: couldn't ZInitialize"); |
---|
336 | log_error(error); |
---|
337 | return(ERROR); /* Oops, couldn't initialize. */ |
---|
338 | } |
---|
339 | |
---|
340 | bzero(¬ice, sizeof(ZNotice_t)); |
---|
341 | |
---|
342 | notice.z_kind = ACKED; |
---|
343 | notice.z_port = 0; |
---|
344 | notice.z_class = class; |
---|
345 | notice.z_class_inst = instance; |
---|
346 | notice.z_sender = 0; |
---|
347 | notice.z_message_len = 0; |
---|
348 | notice.z_recipient = username; |
---|
349 | notice.z_default_format = "Message $message"; |
---|
350 | notice.z_opcode = opcode; |
---|
351 | |
---|
352 | (void) strcpy(buf,signature); |
---|
353 | (void) strcat(buf,message); |
---|
354 | |
---|
355 | |
---|
356 | /* Watch the moving pointer.... */ |
---|
357 | notice.z_message = buf; |
---|
358 | notice.z_message_len = strlen(buf) + 1; |
---|
359 | ret = zsend(¬ice); /* send real message */ |
---|
360 | |
---|
361 | return(ret); |
---|
362 | } |
---|
363 | |
---|
364 | /* |
---|
365 | * Function: zsend(¬ice, isreal): Send a Zephyr notice. |
---|
366 | * Arguments: notice: Zephyr notice to send. |
---|
367 | * Returns: SUCCESS on success, else ERROR |
---|
368 | */ |
---|
369 | |
---|
370 | ERRCODE |
---|
371 | zsend(notice) |
---|
372 | ZNotice_t *notice; |
---|
373 | { |
---|
374 | int ret; |
---|
375 | ZNotice_t retnotice; |
---|
376 | |
---|
377 | if ((ret = ZSendNotice(notice, ZAUTH)) != ZERR_NONE) |
---|
378 | { |
---|
379 | /* Some sort of unknown communications error. */ |
---|
380 | fprintf(stderr, "zsend: error %d from ZSendNotice", ret); |
---|
381 | return(ERROR); |
---|
382 | } |
---|
383 | |
---|
384 | if ((ret = ZIfNotice(&retnotice, (struct sockaddr_in *) 0, |
---|
385 | ZCompareUIDPred, (char *) ¬ice->z_uid)) != |
---|
386 | ZERR_NONE) |
---|
387 | { |
---|
388 | /* Server acknowledgement error here. */ |
---|
389 | fprintf(stderr, "zsend: error %d from ZIfNotice", ret); |
---|
390 | ZFreeNotice(&retnotice); |
---|
391 | return(ERROR); |
---|
392 | } |
---|
393 | |
---|
394 | if (retnotice.z_kind == SERVNAK) |
---|
395 | { |
---|
396 | fprintf(stderr, "zsend: authentication failure"); |
---|
397 | ZFreeNotice(&retnotice); |
---|
398 | return(ERROR); |
---|
399 | } |
---|
400 | |
---|
401 | if (retnotice.z_kind != SERVACK || !retnotice.z_message_len) |
---|
402 | { |
---|
403 | fprintf(stderr, "zsend: server failure during SERVACK"); |
---|
404 | ZFreeNotice(&retnotice); |
---|
405 | return(ERROR); |
---|
406 | } |
---|
407 | |
---|
408 | if (! strcmp(retnotice.z_message, ZSRVACK_SENT)) |
---|
409 | { |
---|
410 | ZFreeNotice(&retnotice); |
---|
411 | return(SUCCESS); /* Message made it */ |
---|
412 | } |
---|
413 | else |
---|
414 | { |
---|
415 | #ifdef TEST |
---|
416 | printf("zsend: unknown error sending Zephyr message"); |
---|
417 | #endif |
---|
418 | ZFreeNotice(&retnotice); |
---|
419 | return(ERROR); /* Some error, probably not using Zephyr */ |
---|
420 | } |
---|
421 | } |
---|
422 | |
---|
423 | |
---|
424 | |
---|
425 | #endif ZEPHYR |
---|
426 | |
---|
427 | /* |
---|
428 | * Function: perror() similar to that of the C library, except that |
---|
429 | * a datestamp precedes the message printed. |
---|
430 | * Arguments: msg: Message to print. |
---|
431 | * Returns: nothing |
---|
432 | * |
---|
433 | */ |
---|
434 | |
---|
435 | #include <sys/uio.h> |
---|
436 | extern int sys_nerr; |
---|
437 | extern char *sys_errlist[]; |
---|
438 | extern int errno; |
---|
439 | static char time_buf[20]; |
---|
440 | |
---|
441 | perror(msg) |
---|
442 | char *msg; |
---|
443 | { |
---|
444 | register int error_number; |
---|
445 | struct iovec iov[6]; |
---|
446 | register struct iovec *v = iov; |
---|
447 | |
---|
448 | error_number = errno; |
---|
449 | |
---|
450 | time_now(time_buf); |
---|
451 | v->iov_base = time_buf; |
---|
452 | v->iov_len = strlen(time_buf); |
---|
453 | v++; |
---|
454 | |
---|
455 | v->iov_base = " "; |
---|
456 | v->iov_len = 1; |
---|
457 | v++; |
---|
458 | |
---|
459 | if (msg) { |
---|
460 | if (*msg) { |
---|
461 | v->iov_base = msg; |
---|
462 | v->iov_len = strlen(msg); |
---|
463 | v++; |
---|
464 | v->iov_base = ": "; |
---|
465 | v->iov_len = 2; |
---|
466 | v++; |
---|
467 | } |
---|
468 | } |
---|
469 | |
---|
470 | if (error_number < sys_nerr) |
---|
471 | v->iov_base = sys_errlist[error_number]; |
---|
472 | else |
---|
473 | v->iov_base = "Unknown error"; |
---|
474 | v->iov_len = strlen(v->iov_base); |
---|
475 | v++; |
---|
476 | |
---|
477 | v->iov_base = "\n"; |
---|
478 | v->iov_len = 1; |
---|
479 | (void) writev(2, iov, (v - iov) + 1); |
---|
480 | } |
---|