dtcm: Resolve CID 87713
[oweals/cde.git] / cde / programs / dtcm / server / callback.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $XConsortium: callback.c /main/5 1996/10/03 10:40:51 drk $ */
24 /*
25  *  (c) Copyright 1993, 1994 Hewlett-Packard Company
26  *  (c) Copyright 1993, 1994 International Business Machines Corp.
27  *  (c) Copyright 1993, 1994 Novell, Inc.
28  *  (c) Copyright 1993, 1994 Sun Microsystems, Inc.
29  */
30
31 #include <EUSCompat.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #include <unistd.h>
36 #include <errno.h>
37 #include <sys/time.h>
38 #include <rpc/rpc.h>
39 #include "agent.h"
40 #include "cmcb.h"
41 #include "callback.h"
42 #include "appt4.h"
43 #include "utility.h"
44 #include "lutil.h"
45
46 extern int debug;
47 extern char *pgname;
48
49 /*
50  * forward declaration of static functions used within the file
51  */
52 static _DtCmsRegistrationInfo * _DtCmsDoCallback(
53         _DtCmsRegistrationInfo  *rlist,
54         uint                    type,
55         char                    *source,
56         int                     pid,
57         int                     version,
58         void                    *args);
59
60 /*****************************************************************************
61  * extern functions
62  *****************************************************************************/
63
64 extern _DtCmsRegistrationInfo *
65 _DtCmsMakeRegistrationInfo(
66         char    *client,
67         int     types,
68         u_long  prognum,
69         u_long  versnum,
70         u_long  procnum,
71         int     pid)
72 {
73         _DtCmsRegistrationInfo *rinfo;
74
75         if ((rinfo = (_DtCmsRegistrationInfo *)calloc(1,
76             sizeof(_DtCmsRegistrationInfo))) == NULL)
77                 return (NULL);
78
79         if ((rinfo->client = strdup(client)) == NULL) {
80                 free(rinfo);
81                 return (NULL);
82         }
83
84         rinfo->types    = types;
85         rinfo->prognum  = prognum;
86         rinfo->versnum  = versnum;
87         rinfo->procnum  = procnum;
88         rinfo->pid      = pid;
89         rinfo->next     = NULL;
90         return(rinfo);
91 }
92
93 extern void
94 _DtCmsFreeRegistrationInfo(_DtCmsRegistrationInfo *rinfo)
95 {
96         if (rinfo==NULL) return;
97         if (rinfo->client != NULL)
98                 free(rinfo->client);
99         free(rinfo);
100 }
101
102 /*
103  * this routine is for v4, so type is not checked
104  */
105 extern _DtCmsRegistrationInfo *
106 _DtCmsGetRegistration(
107         _DtCmsRegistrationInfo  **_rlist,
108         char                    *client,
109         u_long                  prognum,
110         u_long                  versnum,
111         u_long                  procnum,
112         int                     pid)
113 {
114         _DtCmsRegistrationInfo  *rlist = *_rlist, 
115                                 *prev, 
116                                 *ptr, 
117                                 *tmp_ptr;
118
119         for (prev = ptr = rlist; ptr != NULL; ) {
120                 if ((strcmp(ptr->client, client)==0) &&
121                     (ptr->prognum == prognum)  &&
122                     (ptr->versnum == versnum)  &&
123                     (ptr->procnum == procnum))
124                 {
125                         if (ptr->pid == pid) {
126                                 *_rlist = rlist;
127                                 return (ptr);
128                         } else {
129                                 /* ptr points to a stale record
130                                  * remove it from the linked list
131                                  * and update ptr and prev appropriately
132                                  */
133                                 if (ptr == prev) { /* top of list */
134                                         rlist = rlist->next;
135                                         _DtCmsFreeRegistrationInfo(ptr);
136                                         ptr = prev = rlist;
137                                 } else {
138                                         prev->next = ptr->next;
139                                         tmp_ptr = ptr;
140                                         ptr = ptr->next;
141                                         _DtCmsFreeRegistrationInfo(tmp_ptr);
142                                 }
143                         }
144                 } else {
145                         prev = ptr;
146                         ptr = ptr->next;
147                 }
148         }
149
150         *_rlist = rlist;
151         return (NULL);
152 }
153
154 /*
155  * Go through the registration list and ping each client.
156  * Deregister clients that do not respond.
157  */
158 extern _DtCmsRegistrationInfo *
159 _DtCmsCheckRegistrationList(_DtCmsRegistrationInfo *rlist)
160 {
161         int nclients=0, ndereg=0;
162         char *sourcehost=NULL;
163         _DtCmsRegistrationInfo *p_next;
164         _DtCmsRegistrationInfo *p_prev;
165         _DtCmsRegistrationInfo *head;
166         struct timeval timeout_tv;
167         CLIENT *cl;
168         boolean_t advance = B_TRUE;
169
170         timeout_tv.tv_sec = 10;
171         timeout_tv.tv_usec = 0;
172
173         /* loop through the registration list */
174
175         head = p_prev = rlist;
176         while (rlist != NULL) {
177
178                 p_next = rlist->next;
179
180                 if (debug) {
181                         fprintf(stderr,
182                           "%s: pinging %s on prog: %ld, vers: %ld, proc: %ld\n",
183                           pgname, rlist->client, rlist->prognum, rlist->versnum,
184                           rlist->procnum);
185                 }
186
187                 sourcehost = _DtCmsTarget2Location(rlist->client);
188                 cl = clnt_create(sourcehost, rlist->prognum, rlist->versnum,
189                         "udp");
190
191                 if (cl != NULL) {
192                         clnt_control(cl, CLSET_TIMEOUT, (char *)&timeout_tv);
193                         timeout_tv.tv_sec = 5;
194                         clnt_control(cl, CLSET_RETRY_TIMEOUT,
195                                 (char*)&timeout_tv);
196                 }
197                                 
198                 /* no client or client not responding */
199                 if (cl == NULL || clnt_call(cl, 0, (xdrproc_t)xdr_void, (char *)NULL,
200                         (xdrproc_t)xdr_void, (char *)NULL, timeout_tv) != RPC_SUCCESS)
201                 {
202                         if (debug) {
203                                 clnt_pcreateerror(sourcehost);
204                                 fprintf(stderr, "%s: %s deregistered, pid %d\n",
205                                         pgname, rlist->client, rlist->pid);
206                         }
207
208                         if (rlist == p_prev) { /* top of list */
209                                 head = p_next;
210                                 p_prev = p_next;
211                                 advance = B_FALSE;
212                         } else {
213                                 p_prev->next = p_next;
214                         }
215
216                         /* deregister client */
217                         _DtCmsFreeRegistrationInfo(rlist);
218
219                         rlist = p_prev;
220
221                         ndereg++;
222                 }
223
224                 if (cl)
225                         clnt_destroy(cl);
226
227                 free(sourcehost);
228                 nclients++;
229
230                 if (advance) {
231                         p_prev = rlist;
232                         rlist = p_next;
233                 } else
234                         advance = B_TRUE;
235         }
236
237         if (debug) {
238                 fprintf(stderr, "%s: number of clients before cleanup = %d\n",
239                         pgname, nclients);
240                 fprintf(stderr, "%s: number of clients deregistered = %d\n",
241                         pgname, ndereg);
242         }
243
244         return (head);
245 }
246
247 extern _DtCmsRegistrationInfo *
248 _DtCmsDoV1CbForV4Data(
249         _DtCmsRegistrationInfo  *rlist,
250         char                    *source,
251         int                     pid,
252         cms_key                 *key1,
253         cms_key                 *key2)
254 {
255         Appt_4  appt1, appt2;
256
257         if (rlist == NULL)
258                 return (rlist);
259
260         appt1.appt_id.tick = key1->time;
261         appt1.appt_id.key = key1->id;
262
263         if (key2) {
264                 appt2.appt_id.tick = key2->time;
265                 appt2.appt_id.key = key2->id;
266                 appt2.next = NULL;
267                 appt1.next = &appt2;
268         } else
269                 appt1.next = NULL;
270
271         return (_DtCmsDoV1Callback(rlist, source, pid, &appt1));
272 }
273
274 /*
275  * this routine takes care of callbacks to clients using v1 of the callback
276  * protocol.
277  */
278 extern _DtCmsRegistrationInfo *
279 _DtCmsDoV1Callback(
280         _DtCmsRegistrationInfo  *rlist,
281         char                    *source,
282         int                     pid,
283         Appt_4                  *a)
284 {
285         Uid_4 *k, *ids = NULL;
286         Table_Res_4 res;
287         int nclients=0, ncallbacks=0;
288         char *sourcehost=NULL;
289         _DtCmsRegistrationInfo *ptr;
290         _DtCmsRegistrationInfo *prev;
291         struct timeval timeout_tv;
292         CLIENT *cl;
293         boolean_t advance = B_TRUE;
294
295         if (rlist == NULL)
296                 return (rlist);
297
298         /* Callback with appointment ids only for security reason. */
299         while (a != NULL)
300         {
301                 if ((k = (Uid_4 *)malloc(sizeof(Uid_4))) == NULL) {
302                         _DtCm_free_keyentry4(ids);
303                         return (rlist);
304                 }
305
306                 k->appt_id = a->appt_id;
307                 k->next = ids;
308                 ids = k;
309                 a = a->next;
310         }
311
312         res.status = access_ok_4;
313         res.res.tag = ID_4;
314         res.res.Table_Res_List_4_u.i = ids;
315
316         rlist = _DtCmsDoCallback(rlist, 0, source, pid, AGENTVERS, (void *)&res);
317
318         if (ids != NULL)
319                 _DtCm_free_keyentry4(ids);
320
321         return (rlist);
322 }
323
324 extern void
325 _DtCmsListRegistration(_DtCmsRegistrationInfo *rlist, char *cal)
326 {
327         int n = 0;
328
329         fprintf(stderr, "registration list of calendar %s\n", cal);
330         while(rlist != NULL) {
331                 n++;
332                 fprintf(stderr, "\t%s (pid %d)\n", rlist->client, rlist->pid);
333                 rlist = rlist->next;
334         }
335         fprintf(stderr, "\tnumber of registered clients = %d\n", n);
336 }
337
338 extern _DtCmsRegistrationInfo *
339 _DtCmsRemoveRegistration(
340         _DtCmsRegistrationInfo *rlist,
341         _DtCmsRegistrationInfo *rinfo)
342 {
343         _DtCmsRegistrationInfo *ptr, *prev;
344
345
346         for (ptr = prev = rlist; ptr != NULL; prev = ptr, ptr = ptr->next) {
347                 if (ptr == rinfo) {
348                         if (ptr == rlist)
349                                 rlist = ptr->next;
350                         else
351                                 prev->next = ptr->next;
352
353                         _DtCmsFreeRegistrationInfo(ptr);
354                         break;
355                 }
356         }
357
358         return (rlist);
359 }
360
361 extern _DtCmsRegistrationInfo *
362 _DtCmsDoOpenCalCallback(
363         _DtCmsRegistrationInfo  *rlist,
364         char                    *cal,
365         char                    *user,
366         int                     pid)
367 {
368         cmcb_update_callback_args args;
369         char calendar[BUFSIZ];
370
371         if (rlist == NULL)
372                 return (rlist);
373
374         sprintf(calendar, "%s@%s", cal, _DtCmGetLocalHost());
375         args.calendar = calendar;
376         args.user = user;
377         args.data.reason = CSA_CB_CALENDAR_LOGON;
378
379         return (_DtCmsDoCallback(rlist, CSA_CB_CALENDAR_LOGON, user, pid,
380                 AGENTVERS_2, (void *)&args));
381 }
382
383
384 extern _DtCmsRegistrationInfo *
385 _DtCmsDoRemoveCalCallback(
386         _DtCmsRegistrationInfo  *rlist,
387         char                    *cal,
388         char                    *user,
389         int                     pid)
390 {
391         cmcb_update_callback_args args;
392         char calendar[BUFSIZ];
393
394         if (rlist == NULL)
395                 return (rlist);
396
397         sprintf(calendar, "%s@%s", cal, _DtCmGetLocalHost());
398         args.calendar = calendar;
399         args.user = user;
400         args.data.reason = CSA_CB_CALENDAR_DELETED;
401
402         return (_DtCmsDoCallback(rlist, CSA_CB_CALENDAR_DELETED, user, pid,
403                 AGENTVERS_2, (void *)&args));
404 }
405
406 extern _DtCmsRegistrationInfo *
407 _DtCmsDoUpdateCalAttrsCallback(
408         _DtCmsRegistrationInfo  *rlist,
409         char                    *cal,
410         char                    *user,
411         uint                    num_attrs,
412         cms_attribute           *attrs,
413         int                     pid)
414 {
415         cmcb_update_callback_args       args;
416         cmcb_cal_attr_data              cdata; 
417         _DtCmsRegistrationInfo          *res;
418         char buf[80];
419         char calendar[BUFSIZ];
420         int i;
421
422         if (rlist == NULL)
423                 return (rlist);
424
425         sprintf(calendar, "%s@%s", cal, _DtCmGetLocalHost());
426
427         /* set up update info */
428         if (num_attrs > 0 &&
429             (cdata.names = (char **)calloc(1, sizeof(char *)*num_attrs)))
430         {
431                 for (i = 0; i < num_attrs; i++)
432                         cdata.names[i] = attrs[i].name.name;
433         } else {
434                 cdata.num_names = 0;
435                 cdata.names = NULL;
436         }
437
438         args.calendar = calendar;
439         args.user = user;
440         args.data.reason = CSA_CB_CALENDAR_ATTRIBUTE_UPDATED;
441         args.data.data.cdata = &cdata;
442
443         res = _DtCmsDoCallback(rlist, CSA_CB_CALENDAR_ATTRIBUTE_UPDATED, user,
444                 pid, AGENTVERS_2, (void *)&args);
445
446         if (num_attrs > 0) free(cdata.names);
447
448         return (res);
449 }
450
451 extern _DtCmsRegistrationInfo *
452 _DtCmsDoInsertEntryCallback(
453         _DtCmsRegistrationInfo  *rlist,
454         char                    *cal,
455         char                    *source,
456         long                    id,
457         int                     pid)
458 {
459         cmcb_update_callback_args args;
460         cmcb_add_entry_data adata; 
461         char buf[80];
462         char calendar[BUFSIZ];
463
464         if (rlist == NULL)
465                 return (rlist);
466
467         sprintf(calendar, "%s@%s", cal, _DtCmGetLocalHost());
468
469         /* set up update info */
470         sprintf(buf, "%ld", id);
471         adata.id = buf;
472         args.calendar = calendar;
473         args.user = source;
474         args.data.reason = CSA_CB_ENTRY_ADDED;
475         args.data.data.adata = &adata;
476
477         return (_DtCmsDoCallback(rlist, CSA_CB_ENTRY_ADDED, source, pid,
478                 AGENTVERS_2, (void *)&args));
479 }
480
481 extern _DtCmsRegistrationInfo *
482 _DtCmsDoDeleteEntryCallback(
483         _DtCmsRegistrationInfo  *rlist,
484         char                    *cal,
485         char                    *source,
486         long                    id,
487         int                     scope,
488         time_t time,
489         int                     pid)
490 {
491         cmcb_update_callback_args args;
492         cmcb_delete_entry_data ddata; 
493         char buf[80];
494         char calendar[BUFSIZ];
495
496         if (rlist == NULL)
497                 return (rlist);
498
499         sprintf(calendar, "%s@%s", cal, _DtCmGetLocalHost());
500
501         /* set up update info */
502         sprintf(buf, "%ld", id);
503         ddata.id = buf;
504         ddata.scope = scope;
505         ddata.time = time;
506         args.calendar = calendar;
507         args.user = source;
508         args.data.reason = CSA_CB_ENTRY_DELETED;
509         args.data.data.ddata = &ddata;
510
511         return (_DtCmsDoCallback(rlist, CSA_CB_ENTRY_DELETED, source, pid,
512                 AGENTVERS_2, (void *)&args));
513 }
514
515 extern _DtCmsRegistrationInfo *
516 _DtCmsDoUpdateEntryCallback(
517         _DtCmsRegistrationInfo  *rlist,
518         char                    *cal,
519         char                    *source,
520         long                    newid,
521         long                    oldid,
522         int                     scope,
523         long                    time,
524         int                     pid)
525 {
526         cmcb_update_callback_args args;
527         cmcb_update_entry_data udata; 
528         char nbuf[80], obuf[80];
529         char calendar[BUFSIZ];
530
531         if (rlist == NULL)
532                 return (rlist);
533
534         sprintf(calendar, "%s@%s", cal, _DtCmGetLocalHost());
535
536         /* set up update info */
537         sprintf(obuf, "%ld", oldid);
538         udata.oldid = obuf;
539         if (newid > 0)
540                 sprintf(nbuf, "%ld", newid);
541         else
542                 nbuf[0] = '\0';
543         udata.newid = nbuf;
544         udata.scope = scope;
545         udata.time = time;
546         args.calendar = calendar;
547         args.user = source;
548         args.data.reason = CSA_CB_ENTRY_UPDATED;
549         args.data.data.udata = &udata;
550
551         return (_DtCmsDoCallback(rlist, CSA_CB_ENTRY_UPDATED, source, pid,
552                 AGENTVERS_2, (void *)&args));
553 }
554
555 /*
556  * this routine takes care of callbacks to clients using either
557  * v1 or v2 of the callback protocol.
558  */
559 static _DtCmsRegistrationInfo *
560 _DtCmsDoCallback(
561         _DtCmsRegistrationInfo  *rlist,
562         uint                    type,
563         char                    *source,
564         int                     pid,
565         int                     version,
566         void                    *args)
567 {
568         int nclients=0, ncallbacks=0;
569         char *sourcehost=NULL;
570         _DtCmsRegistrationInfo *ptr;
571         _DtCmsRegistrationInfo *prev;
572         struct timeval timeout_tv;
573         CLIENT *cl;
574         boolean_t advance = B_TRUE;
575         
576         /*
577          * loop through the registration list looking for parties
578          * interested in this transaction.
579          */
580
581         for (ptr = prev = rlist; ptr != NULL; ) {
582
583                 /* The caller will get the results of the rpc call.
584                  * If he's registered on the callback list, don't call him -
585                  * UNLESS the process id of his client differs from the
586                  * original ticket. However, if the pid is a VOIDPID (-1),
587                  * a version 2 client has registered and there's no way
588                  * of telling which instance of the client it is.  So,
589                  * to be safe (avoid deadlock) we won't callback version
590                  * 2 clients registered on version 3 daemons if their
591                  * registration name entry matches the caller's. [Nanno]
592                  */
593
594                 if (version != ptr->versnum ||
595                     (type && !(type & ptr->types)) ||
596                     ((strcmp(source, ptr->client) == 0) &&
597                     ((pid == ptr->pid) || (pid == -1 ) || (ptr->pid == -1)))) {
598                         prev = ptr;
599                         ptr = ptr->next;
600                         nclients++;
601                         continue;
602                 }
603
604                 sourcehost = _DtCmsTarget2Location(ptr->client);
605                 if (debug) {
606                         fprintf(stderr,
607                           "%s: calling back %s on prog: %ld, vers: %ld, proc: %ld\n",
608                           pgname, ptr->client, ptr->prognum, ptr->versnum,
609                           ptr->procnum);
610                 }
611                 cl = clnt_create(sourcehost, ptr->prognum, ptr->versnum, "udp");
612
613                 /* deregister client if fails to create handle */
614                 if (cl == NULL) {
615                         if (debug) {
616                                 clnt_pcreateerror(sourcehost);
617                         }
618
619                         if (ptr == rlist) { /* top of list */
620                                 rlist = ptr->next;
621                                 prev = rlist;
622                                 advance = B_FALSE;
623                         } else {
624                                 prev->next = ptr->next;
625                         }
626
627                         /* deregister client */
628                         _DtCmsFreeRegistrationInfo(ptr);
629
630                         ptr = prev;
631
632                 } else {
633                         /* Set timeout to zero so that the call
634                          * returns right away.
635                          */
636                         timeout_tv.tv_sec = 0;
637                         timeout_tv.tv_usec = 0;
638
639 #ifndef SunOS
640                         /* for non-sun systems, clnt_call won't
641                          * return right away unless timeout is set
642                          * to zero using clnt_control(), (rpc bug?)
643                          */
644                         clnt_control(cl, CLSET_TIMEOUT,
645                                         (char *)&timeout_tv);
646 #endif
647                         if (version == AGENTVERS) {
648                                 (void)clnt_call(cl, ptr->procnum,
649                                         (xdrproc_t)_DtCm_xdr_Table_Res_4, (char *)args,
650                                         (xdrproc_t)xdr_void, (char *)0, timeout_tv);
651                         } else if (version == AGENTVERS_2) {
652                                 (void)clnt_call(cl, ptr->procnum,
653                                         (xdrproc_t)xdr_cmcb_update_callback_args,
654                                         (char *)args, (xdrproc_t)xdr_void, (char *)0,
655                                         timeout_tv);
656                         }
657                         ncallbacks++;
658                         nclients++;
659                 }
660
661                 if (cl)
662                         clnt_destroy(cl);
663
664                 free(sourcehost);
665
666                 if (advance) {
667                         prev = ptr;
668                         ptr = ptr->next;
669                 } else
670                         advance = B_TRUE;
671         }
672
673         if (debug) {
674                 fprintf(stderr, "%s: number of registered clients = %d\n",
675                         pgname, nclients);
676                 fprintf(stderr, "%s: number of clients called back= %d\n",
677                         pgname, ncallbacks);
678         }
679
680         return (rlist);
681 }
682