2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
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)
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
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these libraries and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $TOG: agent.c /main/2 1998/03/16 14:42:16 mgreess $ */
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.
31 #include <EUSCompat.h>
37 #if !defined(__linux__) && !defined(CSRG_BASED)
41 #include <netconfig.h>
44 #include <sys/signal.h>
45 #include <sys/socket.h>
46 #include <sys/errno.h>
48 #include <X11/Intrinsic.h>
60 * - contain update information from backend
62 typedef struct cb_info {
71 static _CallbackInfo *cb_head = NULL, *cb_tail = NULL;
73 u_long _DtCm_transient = 0;
75 static u_long prognum = 0x40000000;
76 static int mapped = 0;
78 /******************************************************************************
79 * forward declaration of static functions used within the file
80 ******************************************************************************/
82 static u_long gettransient (u_long version);
84 static u_long gettransient (int proto, u_long vers, int *sockp);
86 static void _DtCm_handle_callback();
87 static CSA_return_code _ConvertCallbackData(cmcb_update_callback_args *args,
89 static CSA_return_code _CopyAttributeNames(uint fnum, char **fnames,
90 CSA_uint32 *tnum, char ***tnames);
91 static boolean_t _ProcessV1Callback(_CallbackInfo *ptr);
92 static boolean_t _ProcessV2Callback(_CallbackInfo *ptr);
93 static void _FreeCallbackInfo(_CallbackInfo *ptr);
95 /*****************************************************************************
96 * extern functions used in the library
97 *****************************************************************************/
100 * Register rpc service for server callback
103 _DtCm_init_agent(void)
107 #if defined(SunOS) && SunOS < 55
108 extern boolean_t rpc_reg(const u_long, const u_long, const u_long,
109 const char *(*)(), const xdrproc_t, const xdrproc_t,
114 extern void (*sigset(int, void (*)(int)))(int);
116 extern void (*sigset())();
119 /* locking candidate for MT-safe purpose */
123 DP(("libdtcm: _DtCm_init_agent\n"));
126 (void)rpcb_unset(_DtCm_transient, AGENTVERS, NULL);
127 if ((_DtCm_transient = gettransient((u_long)1)) == 0) {
128 _DtCm_print_errmsg("Cannot get transient program number\n");
129 _DtCm_print_errmsg("Callback cannot be enabled.\n");
133 /* register v1 callback */
134 if (rpc_reg(_DtCm_transient, AGENTVERS, update_callback,
135 (const char *(*)())_DtCm_update_callback_1, _DtCm_xdr_Table_Res_4,
136 _DtCm_xdr_Update_Status, "udp") == -1) {
137 _DtCm_print_errmsg("Cannot register v1 callback handler\n");
138 _DtCm_print_errmsg("Callback cannot be enabled.\n");
141 /* register v2 callback */
142 if (rpc_reg(_DtCm_transient, AGENTVERS_2, CMCB_UPDATE_CALLBACK,
143 (const char *(*)())cmcb_update_callback_2_svc,
144 xdr_cmcb_update_callback_args, xdr_void, "udp") == -1) {
145 _DtCm_print_errmsg("Cannot register v2 callback handler\n");
146 _DtCm_print_errmsg("Callback cannot be enabled.\n");
150 (void)pmap_unset(_DtCm_transient, AGENTVERS);
151 if ((_DtCm_transient = gettransient(IPPROTO_UDP,(u_long)1, &s)) == 0) {
152 _DtCm_print_errmsg("Cannot get transient program number\n");
153 _DtCm_print_errmsg("Callback cannot be enabled.\n");
157 if (registerrpc(_DtCm_transient, AGENTVERS, update_callback,
158 (char *(*)())_DtCm_update_callback_1, (xdrproc_t)_DtCm_xdr_Table_Res_4,
159 (xdrproc_t)_DtCm_xdr_Update_Status) == -1) {
160 _DtCm_print_errmsg("Cannot register v1 callback handler\n");
161 _DtCm_print_errmsg("Callback cannot be enabled.\n");
164 if (registerrpc(_DtCm_transient, AGENTVERS_2, CMCB_UPDATE_CALLBACK,
165 (char *(*)())cmcb_update_callback_2_svc,
166 (xdrproc_t)xdr_cmcb_update_callback_args, (xdrproc_t)xdr_void) == -1) {
167 _DtCm_print_errmsg("Cannot register v2 callback handler\n");
168 _DtCm_print_errmsg("Callback cannot be enabled.\n");
173 /* locking candidate for MT-safe purpose */
178 * Unregister with the rpc service.
181 _DtCm_destroy_agent(void)
186 DP(("libdtcm: _DtCm_destroy_agent\n"));
189 (void) rpcb_unset(_DtCm_transient, AGENTVERS, NULL);
190 (void) rpcb_unset(_DtCm_transient, AGENTVERS_2, NULL);
192 (void) pmap_unset(_DtCm_transient, AGENTVERS);
193 (void) pmap_unset(_DtCm_transient, AGENTVERS_2);
196 /* locking candidate for MT-safe purpose */
201 _DtCm_process_updates(void)
203 #if defined(CSRG_BASED) || defined(__linux__)
208 rpc_bits = svc_fdset;
210 nfd = select(FD_SETSIZE, &rpc_bits, NULL, NULL, NULL);
217 for (i = 0; i < FD_SETSIZE; i++) {
218 if (FD_ISSET(i, &rpc_bits)) {
219 svc_getreqset(&rpc_bits);
229 fd_mask fmask, *inbits;
230 struct pollfd pfd[FD_SETSIZE];
236 rpc_bits = svc_fdset;
238 /* convert to pollfd structure */
239 inbits = rpc_bits.fds_bits;
241 for (i = 0; i < FD_SETSIZE; i += NFDBITS) {
243 for (j = 0; fmask != 0 ; j++, fmask >>= 1) {
246 if (p->fd >= FD_SETSIZE)
255 /* poll and return right away */
258 nfd = poll(pfd, i, 0);
264 /* if set, handle rpc calls */
266 /* convert back to fd_set structure */
270 for (p = pfd; i-- > 0; p++) {
273 inbits = &rpc_bits.fds_bits[j];
276 if (p->revents & POLLIN) {
277 *inbits |= (1 << (p->fd % NFDBITS));
283 svc_getreqset(&rpc_bits);
285 #endif /* CSRG_BASED || linux */
289 * The server calls this routine when an update event occurs;
290 * It's job is to notify CM asynchronously that an
291 * update has occurred. It has to do it this
292 * way (i.e. raise a signal) because the client
293 * can't make an rpc call until this procedure call has
294 * returned to the server.
298 _DtCm_update_callback_1(Table_Res_4 *t, _DtCm_Connection *conn)
300 static Update_Status status = update_succeeded;
303 DP(("agent.c: _DtCm_update_callback_1()\n"));
306 * no point to save data for version 4 and before
307 * since the info from old backends does not contain
309 * so we just invoke all registered callback with no data
311 if (cbi = (_CallbackInfo *)calloc(1, sizeof(_CallbackInfo))) {
312 cbi->vers = AGENTVERS;
322 /* handle callback from backend */
323 _DtCm_handle_callback();
329 * Handler for v2 callback protocol
332 cmcb_update_callback_2_svc(cmcb_update_callback_args *args, struct svc_req *d)
336 DP(("agent.c: cmcb_update_callback_2_svc()\n"));
341 if (_ConvertCallbackData(args, &cbi) == CSA_SUCCESS) {
342 cbi->vers = AGENTVERS_2;
351 /* handle callback from backend */
352 _DtCm_handle_callback();
358 /******************************************************************************
359 * static functions used within in the file
360 ******************************************************************************/
363 * get transient program number for callbacks.
367 gettransient (u_long version)
370 struct nd_hostserv host = {HOST_SELF, "rpcbind"};
371 struct nd_addrlist *addrp;
374 struct netconfig *netconf;
376 netconf = getnetconfigent("udp");
378 DP(("(gettransient) getnetconfigent(udp) failed\n"));
379 freenetconfigent(netconf);
383 stat = netdir_getbyname(netconf, &host, &addrp);
385 DP(("(gettransient) netdir_getbyname failed\n"));
386 netdir_free(addrp, ND_ADDRLIST);
387 freenetconfigent(netconf);
391 if (addrp->n_cnt < 1) {
392 DP(("(gettransient) netdir_getbyname - zero addresses\n"));
393 netdir_free(addrp, ND_ADDRLIST);
394 freenetconfigent(netconf);
398 addr = addrp->n_addrs;
400 while (!rpcb_set(prognum++, version, netconf, addr))
402 netdir_free(addrp, ND_ADDRLIST);
403 freenetconfigent(netconf);
412 gettransient (int proto, u_long vers, int *sockp)
416 struct sockaddr_in addr;
420 socktype = SOCK_DGRAM;
423 socktype = SOCK_STREAM;
426 DP(("unknown protocol type\n"));
430 if (*sockp == RPC_ANYSOCK) {
431 if ((s = socket(AF_INET, socktype, 0)) < 0) {
439 addr.sin_addr.s_addr = 0;
440 addr.sin_family = AF_INET;
444 if (bind(s, (struct sockaddr *)&addr, len) != 0) {
449 if (getsockname(s, (struct sockaddr *)&addr, &len) < 0) {
450 perror("getsockname");
454 while (!pmap_set(prognum++, vers, proto, ntohs(addr.sin_port)))
460 #endif /* not SunOS */
463 _DtCm_handle_callback(void)
465 _CallbackInfo *ptr, *prev;
466 boolean_t keep = B_FALSE;
468 DP(("agent.c: _DtCm_handle_callback()\n"));
470 for (ptr = cb_head, prev = NULL; ptr != NULL; ) {
471 /* we only handle version 1 and version 2 */
472 if (ptr->vers == AGENTVERS)
473 keep = _ProcessV1Callback(ptr);
475 keep = _ProcessV2Callback(ptr);
481 prev->next = ptr->next;
483 _FreeCallbackInfo(ptr);
484 ptr = NULL; /* freed by _FreeCallbackInfo() */
495 static CSA_return_code
496 _ConvertCallbackData(cmcb_update_callback_args *args, _CallbackInfo **cbi)
499 CSA_calendar_user *user;
500 CSA_logon_callback_data *ldata;
501 CSA_calendar_deleted_callback_data *rdata;
502 CSA_calendar_attr_update_callback_data *cdata;
503 CSA_add_entry_callback_data *adata;
504 CSA_delete_entry_callback_data *ddata;
505 CSA_update_entry_callback_data *udata;
506 char timebuf[BUFSIZ];
508 if ((ncbi = (_CallbackInfo *)calloc(1, sizeof(_CallbackInfo))) == NULL)
509 return (CSA_E_INSUFFICIENT_MEMORY);
511 if (args->calendar && (ncbi->cal = strdup(args->calendar)) == NULL) {
513 return (CSA_E_INSUFFICIENT_MEMORY);
516 if (args->user && (ncbi->user = strdup(args->user)) == NULL) {
517 _FreeCallbackInfo(ncbi);
518 return (CSA_E_INSUFFICIENT_MEMORY);
521 if ((user = (CSA_calendar_user *)calloc(1, sizeof(CSA_calendar_user)))
523 _FreeCallbackInfo(ncbi);
524 return (CSA_E_INSUFFICIENT_MEMORY);
526 user->user_name = ncbi->user;
528 ncbi->reason = args->data.reason;
529 switch (ncbi->reason) {
530 case CSA_CB_CALENDAR_LOGON:
531 if ((ldata = (CSA_logon_callback_data *)calloc(1,
532 sizeof(CSA_logon_callback_data))) == NULL) {
534 _FreeCallbackInfo(ncbi);
535 return (CSA_E_INSUFFICIENT_MEMORY);
538 ncbi->data = (void *)ldata;
541 case CSA_CB_CALENDAR_DELETED:
542 if ((rdata = (CSA_calendar_deleted_callback_data *)calloc(1,
543 sizeof(CSA_calendar_deleted_callback_data))) == NULL) {
545 _FreeCallbackInfo(ncbi);
546 return (CSA_E_INSUFFICIENT_MEMORY);
549 ncbi->data = (void *)rdata;
552 case CSA_CB_CALENDAR_ATTRIBUTE_UPDATED:
553 if ((cdata = (CSA_calendar_attr_update_callback_data *)
555 CSA_calendar_attr_update_callback_data))) == NULL) {
557 _FreeCallbackInfo(ncbi);
558 return (CSA_E_INSUFFICIENT_MEMORY);
561 ncbi->data = (void *)cdata;
563 if (_CopyAttributeNames(args->data.data.cdata->num_names,
564 args->data.data.cdata->names, &cdata->number_attributes,
565 &cdata->attribute_names)) {
566 _FreeCallbackInfo(ncbi);
567 return (CSA_E_INSUFFICIENT_MEMORY);
572 case CSA_CB_ENTRY_ADDED:
573 if ((adata = (CSA_add_entry_callback_data *)calloc(1,
574 sizeof(CSA_add_entry_callback_data))) == NULL) {
576 _FreeCallbackInfo(ncbi);
577 return (CSA_E_INSUFFICIENT_MEMORY);
580 ncbi->data = (void *)adata;
582 if (args->data.data.adata->id && (adata->added_entry_id.data =
583 (unsigned char *)strdup(args->data.data.adata->id))
585 _FreeCallbackInfo(ncbi);
586 return (CSA_E_INSUFFICIENT_MEMORY);
588 adata->added_entry_id.size =
589 strlen((char *)adata->added_entry_id.data);
593 case CSA_CB_ENTRY_DELETED:
594 if ((ddata = (CSA_delete_entry_callback_data *)calloc(1,
595 sizeof(CSA_delete_entry_callback_data))) == NULL) {
597 _FreeCallbackInfo(ncbi);
598 return (CSA_E_INSUFFICIENT_MEMORY);
601 ncbi->data = (void *)ddata;
603 if (args->data.data.ddata->id && (ddata->deleted_entry_id.data =
604 (unsigned char *)strdup(args->data.data.ddata->id))
606 _FreeCallbackInfo(ncbi);
607 return (CSA_E_INSUFFICIENT_MEMORY);
609 ddata->deleted_entry_id.size =
610 strlen((char *)ddata->deleted_entry_id.data);
612 _csa_tick_to_iso8601(args->data.data.ddata->time, timebuf);
613 if ((ddata->date_and_time = strdup(timebuf)) == NULL) {
614 _FreeCallbackInfo(ncbi);
615 return (CSA_E_INSUFFICIENT_MEMORY);
618 ddata->scope = args->data.data.ddata->scope;
621 case CSA_CB_ENTRY_UPDATED:
622 if ((udata = (CSA_update_entry_callback_data *)calloc(1,
623 sizeof(CSA_update_entry_callback_data))) == NULL) {
625 _FreeCallbackInfo(ncbi);
626 return (CSA_E_INSUFFICIENT_MEMORY);
629 ncbi->data = (void *)udata;
631 if (args->data.data.udata->newid && (udata->new_entry_id.data =
632 (unsigned char *)strdup(args->data.data.udata->newid))
634 _FreeCallbackInfo(ncbi);
635 return (CSA_E_INSUFFICIENT_MEMORY);
637 udata->new_entry_id.size =
638 strlen((char *)udata->new_entry_id.data);
640 if (args->data.data.udata->oldid && (udata->old_entry_id.data =
641 (unsigned char *)strdup(args->data.data.udata->oldid))
643 _FreeCallbackInfo(ncbi);
644 return (CSA_E_INSUFFICIENT_MEMORY);
646 udata->old_entry_id.size =
647 strlen((char *)udata->old_entry_id.data);
649 _csa_tick_to_iso8601(args->data.data.udata->time, timebuf);
650 if ((udata->date_and_time = strdup(timebuf)) == NULL) {
651 _FreeCallbackInfo(ncbi);
652 return (CSA_E_INSUFFICIENT_MEMORY);
655 udata->scope = args->data.data.udata->scope;
660 return (CSA_SUCCESS);
663 static CSA_return_code
664 _CopyAttributeNames(uint fnum, char **fnames, CSA_uint32 *tnum, char ***tnames)
672 return (CSA_SUCCESS);
675 if ((nnames = calloc(1, sizeof(char *) * fnum)) == NULL)
676 return (CSA_E_INSUFFICIENT_MEMORY);
678 for (i = 0; i < fnum; i++) {
679 if ((nnames[i] = strdup(fnames[i])) == NULL)
686 return (CSA_SUCCESS);
688 _DtCm_free_character_pointers(i, nnames);
690 return (CSA_E_INSUFFICIENT_MEMORY);
695 * pre callback protocol V2, there is no distinction
696 * between different reasons, and no data passed. So
697 * there's only one possible thing to do, and that's
698 * run all the callbacks.
701 _ProcessV1Callback(_CallbackInfo *ptr)
704 _DtCmCallbackEntry *cb;
705 boolean_t keep = B_FALSE;
707 for (cal = _DtCm_active_cal_list; cal != NULL; cal = cal->next) {
708 if (cal->rpc_version >= _DtCM_FIRST_EXTENSIBLE_SERVER_VERSION)
711 if (cal->do_reasons &
712 (CSA_CB_ENTRY_ADDED | CSA_CB_ENTRY_DELETED |
713 CSA_CB_ENTRY_UPDATED))
715 /* only do dumb processing if it was a V4 server */
716 for (cb = cal->cb_list; cb != NULL; cb = cb->next) {
717 if (cal->do_reasons & cb->reason) {
718 cb->handler((CSA_session_handle)cal,
719 cal->do_reasons & cb->reason,
722 (CSA_extension*) NULL);
725 } else if (cal->all_reasons & (CSA_CB_ENTRY_ADDED |
726 CSA_CB_ENTRY_DELETED | CSA_CB_ENTRY_UPDATED))
734 _ProcessV2Callback(_CallbackInfo *ptr)
737 _DtCmCallbackEntry *cb;
738 boolean_t keep = B_FALSE;
740 for (cal = _DtCm_active_cal_list; cal != NULL; cal = cal->next) {
741 if (cal->rpc_version < _DtCM_FIRST_EXTENSIBLE_SERVER_VERSION ||
742 strcmp(ptr->cal, cal->name))
745 if (cal->do_reasons & ptr->reason) {
747 /* only do dumb processing if it was a V4 server */
748 for (cb = cal->cb_list; cb != NULL; cb = cb->next) {
749 if (ptr->reason & cb->reason) {
750 cb->handler((CSA_session_handle)cal,
752 (CSA_buffer)ptr->data,
754 (CSA_extension*) NULL);
757 } else if (cal->all_reasons & ptr->reason)
765 _FreeCallbackInfo(_CallbackInfo *ptr)
767 CSA_logon_callback_data *ldata;
768 CSA_calendar_deleted_callback_data *rdata;
769 CSA_calendar_attr_update_callback_data *cdata;
770 CSA_add_entry_callback_data *adata;
771 CSA_delete_entry_callback_data *ddata;
772 CSA_update_entry_callback_data *udata;
775 if (ptr->cal) free(ptr->cal);
776 if (ptr->user) free(ptr->user);
778 if (ptr->data) switch (ptr->reason) {
779 case CSA_CB_CALENDAR_LOGON:
781 if (ldata->user) free(ldata->user);
784 case CSA_CB_CALENDAR_DELETED:
786 if (rdata->user) free(rdata->user);
789 case CSA_CB_CALENDAR_ATTRIBUTE_UPDATED:
790 cdata = (CSA_calendar_attr_update_callback_data *)
792 if (cdata->user) free(cdata->user);
793 if (cdata->number_attributes > 0)
794 _DtCm_free_character_pointers(
795 cdata->number_attributes,
796 cdata->attribute_names);
799 case CSA_CB_ENTRY_ADDED:
800 adata = (CSA_add_entry_callback_data *)ptr->data;
801 if (adata->user) free(adata->user);
802 if (adata->added_entry_id.data)
803 free(adata->added_entry_id.data);
806 case CSA_CB_ENTRY_DELETED:
807 ddata = (CSA_delete_entry_callback_data *)ptr->data;
808 if (ddata->date_and_time) free(ddata->date_and_time);
809 if (ddata->user) free(ddata->user);
810 if (ddata->deleted_entry_id.data)
811 free(ddata->deleted_entry_id.data);
814 case CSA_CB_ENTRY_UPDATED:
815 udata = (CSA_update_entry_callback_data *)ptr->data;
816 if (udata->user) free(udata->user);
817 if (udata->date_and_time) free(udata->date_and_time);
818 if (udata->old_entry_id.data)
819 free(udata->old_entry_id.data);
820 if (udata->new_entry_id.data)
821 free(udata->new_entry_id.data);