1/* 2 * Copyright (c) 2010 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of Apple Inc. ("Apple") nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 * 30 * Portions of this software have been released under the following terms: 31 * 32 * (c) Copyright 1989-1993 OPEN SOFTWARE FOUNDATION, INC. 33 * (c) Copyright 1989-1993 HEWLETT-PACKARD COMPANY 34 * (c) Copyright 1989-1993 DIGITAL EQUIPMENT CORPORATION 35 * 36 * To anyone who acknowledges that this file is provided "AS IS" 37 * without any express or implied warranty: 38 * permission to use, copy, modify, and distribute this file for any 39 * purpose is hereby granted without fee, provided that the above 40 * copyright notices and this notice appears in all source code copies, 41 * and that none of the names of Open Software Foundation, Inc., Hewlett- 42 * Packard Company or Digital Equipment Corporation be used 43 * in advertising or publicity pertaining to distribution of the software 44 * without specific, written prior permission. Neither Open Software 45 * Foundation, Inc., Hewlett-Packard Company nor Digital 46 * Equipment Corporation makes any representations about the suitability 47 * of this software for any purpose. 48 * 49 * Copyright (c) 2007, Novell, Inc. All rights reserved. 50 * Redistribution and use in source and binary forms, with or without 51 * modification, are permitted provided that the following conditions 52 * are met: 53 * 54 * 1. Redistributions of source code must retain the above copyright 55 * notice, this list of conditions and the following disclaimer. 56 * 2. Redistributions in binary form must reproduce the above copyright 57 * notice, this list of conditions and the following disclaimer in the 58 * documentation and/or other materials provided with the distribution. 59 * 3. Neither the name of Novell Inc. nor the names of its contributors 60 * may be used to endorse or promote products derived from this 61 * this software without specific prior written permission. 62 * 63 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 64 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 65 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 66 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY 67 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 68 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 69 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 70 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 71 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 72 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 73 * 74 * @APPLE_LICENSE_HEADER_END@ 75 */ 76 77/* 78** 79** NAME: 80** 81** conv.c 82** 83** FACILITY: 84** 85** Conversation Manager (CONV) 86** 87** ABSTRACT: 88** 89** Implement conversation manager callback procedures for NCA RPC 90** datagram protocol. 91** 92** 93*/ 94 95#include <dg.h> 96#include <dgccall.h> 97#include <dgccallt.h> 98 99#include <dce/conv.h> 100#include <dgglob.h> 101 102/* ========================================================================= */ 103 104INTERNAL boolean conv_common ( 105 idl_uuid_t * /*actuid*/, 106 unsigned32 /*boot_time*/, 107 rpc_dg_ccall_p_t * /*ccall*/, 108 unsigned32 * /*st*/ 109 ); 110 111/* ========================================================================= */ 112 113/* 114 * C O N V _ C O M M O N 115 * 116 * Common routine used by conv_who_are_you() and conv_are_you_there() 117 * to find the client call handle associated with the incoming callback 118 * and verify that we are communicating with the expected instance of 119 * the server. 120 */ 121 122INTERNAL boolean conv_common 123( 124 idl_uuid_t *actuid, 125 unsigned32 boot_time, 126 rpc_dg_ccall_p_t *ccall, 127 unsigned32 *st 128) 129{ 130 /* 131 * Find the call he's asking about. 132 */ 133 134 *ccall = rpc__dg_ccallt_lookup(actuid, RPC_C_DG_NO_HINT); 135 136 /* 137 * No ccall entry will exist if an old duplicate WAY callback request 138 * is received. If there is no ccall entry corresponding to the 139 * incoming activity id then we return an error status code. The 140 * server performing the WAY callback will detect the error and send 141 * a reject packet that will be dropped by the client. 142 */ 143 144 if (*ccall == NULL) 145 { 146 *st = nca_s_bad_actid; 147 return (false); 148 } 149 150 /* 151 * If we don't know the boot time yet for this server, stash it away 152 * now. 153 */ 154 155 if ((*ccall)->c.call_server_boot == 0) 156 { 157 (*ccall)->c.call_server_boot = boot_time; 158 } 159 else 160 { 161 /* 162 * We DO know the boot time. If what the server's supplied boot 163 * time isn't what we think it should be, then we must be getting 164 * called back by a new instance of the server (i.e., which 165 * received a duplicate of an outstanding request of ours). Since 166 * we can't know whether the original instance of the server 167 * executed our call or not, we return failure to the server 168 * to prevent IT from executing call (i.e., for a possible second 169 * time, violating the "at most once" rule). 170 */ 171 if ((*ccall)->c.call_server_boot != boot_time) 172 { 173 *st = nca_s_you_crashed; 174 RPC_DG_CCALL_RELEASE(ccall); 175 return (false); 176 } 177 } 178 179 *st = rpc_s_ok; 180 return (true); 181} 182 183/* 184 * C O N V _ W H O _ A R E _ Y O U 185 * 186 * This procedure is called remotely by a server that has no "connection" 187 * information about a client from which it has just received a call. This 188 * call executes in the context of that client (i.e. it is a "call back"). 189 * We return the current sequence number of the client and his "identity". 190 * We accept the boot time from the server for later use in calls to the 191 * same server. 192 */ 193 194PRIVATE void conv_who_are_you 195( 196 handle_t h ATTRIBUTE_UNUSED, /* Not really */ 197 idl_uuid_t *actuid, 198 unsigned32 boot_time, 199 unsigned32 *seq, 200 unsigned32 *st 201) 202{ 203 rpc_dg_ccall_p_t ccall; 204 205 RPC_LOCK_ASSERT(0); 206 207 if (! conv_common(actuid, boot_time, &ccall, st)) 208 { 209 return; 210 } 211 212 *seq = ccall->c.call_seq; 213 RPC_DG_CCALL_RELEASE(&ccall); 214} 215 216/* 217 * C O N V _ W H O _ A R E _ Y O U 2 218 * 219 * This procedure is called remotely by a server that needs to monitor the 220 * the liveness of this client. We return to it a UUID unique to this 221 * particular instance of this particular application. We also return all 222 * the information from a normal WAY callback, so that in the future servers 223 * will only need to make this call to get all client information. 224 */ 225 226PRIVATE void conv_who_are_you2 227( 228 handle_t h, /* Not really */ 229 idl_uuid_t *actuid, 230 unsigned32 boot_time, 231 unsigned32 *seq, 232 idl_uuid_t *cas_uuid, 233 unsigned32 *st 234) 235{ 236 conv_who_are_you(h, actuid, boot_time, seq, st); 237 *cas_uuid = rpc_g_dg_my_cas_uuid; 238} 239 240/* 241 * C O N V _ A R E _ Y O U _ T H E R E 242 * 243 * This procedure is called remotely by a server (while in the receive 244 * state) that is trying to verify whether or not it's client is still 245 * alive and sending input data. This call executes in the context of 246 * that client (i.e. it is a "call back"). We check that the client 247 * call is still active and that the boot time from the server matches 248 * that the active CCALL 249 * 250 * Note that only the server side of this callback is currently 251 * implemented. 252 */ 253 254PRIVATE void conv_are_you_there 255( 256 handle_t h ATTRIBUTE_UNUSED, /* Not really */ 257 idl_uuid_t *actuid, 258 unsigned32 boot_time, 259 unsigned32 *st 260) 261{ 262 rpc_dg_ccall_p_t ccall; 263 264 RPC_LOCK_ASSERT(0); 265 266 if (! conv_common(actuid, boot_time, &ccall, st)) 267 { 268 return; 269 } 270 271 RPC_DG_CCALL_RELEASE(&ccall); 272} 273 274/* 275 * C O N V _ W H O _ A R E _ Y O U _ A U T H 276 * 277 * This procedure is called remotely by a server that has no "connection" 278 * information about a client from which it has just received a call, 279 * when the incoming call is authenticated. In addition to the 280 * information returned by conv_who_are_you, a challenge-response 281 * takes place to inform the server of the identity of the client. 282 */ 283 284PRIVATE void conv_who_are_you_auth 285( 286 handle_t h ATTRIBUTE_UNUSED, /* not really */ 287 idl_uuid_t *actuid, 288 unsigned32 boot_time, 289 ndr_byte *in_data, 290 signed32 in_len, 291 signed32 out_max_len, 292 unsigned32 *seq, 293 idl_uuid_t *cas_uuid, 294 ndr_byte *out_data, 295 signed32 *out_len, 296 unsigned32 *st 297) 298{ 299 rpc_dg_ccall_p_t ccall; 300 rpc_dg_auth_epv_p_t epv; 301 ndr_byte *save_out_data = out_data; 302 303 RPC_LOCK_ASSERT(0); 304 305 if (! conv_common(actuid, boot_time, &ccall, st)) 306 { 307 return; 308 } 309 310 *cas_uuid = rpc_g_dg_my_cas_uuid; 311 *seq = ccall->c.call_seq; 312 313 /* 314 * If there's already a credentials buffer associated with this 315 * call handle, free it. We rely on the underlying security code 316 * to do cacheing if appropriate. 317 */ 318 if (ccall->auth_way_info != NULL) 319 { 320 RPC_MEM_FREE(ccall->auth_way_info, RPC_C_MEM_DG_EPAC); 321 ccall->auth_way_info = NULL; 322 ccall->auth_way_info_len = 0; 323 } 324 325 /* 326 * Make sure that we really have an authenticated call here, 327 * lest we dereference null and blow up the process. 328 */ 329 epv = ccall->c.auth_epv; 330 if (epv == NULL) 331 { 332 *st = rpc_s_binding_has_no_auth; 333 } 334 else 335 { 336 RPC_DG_CALL_UNLOCK(&(ccall->c)); 337 RPC_UNLOCK(0); 338 339 (*epv->way_handler) (ccall->c.key_info, in_data, in_len, 340 out_max_len, &out_data, out_len, st); 341 342 RPC_LOCK(0); 343 RPC_DG_CALL_LOCK(&(ccall->c)); 344 345 if (*out_len > out_max_len) 346 { 347 /* 348 * If the credentials did not fit in the buffer provided, 349 * the WAY handler will have alloced up a buffer big enough 350 * to hold them, and returned a pointer to that storage in 351 * out_data. 352 * 353 * Stash a pointer to this buffer in the call handle, copy 354 * as much of the credentials as will fit in the real response 355 * packet, and return a status that indicates that the caller 356 * needs to fetch the rest of the credentials. 357 */ 358 ccall->auth_way_info = out_data; 359 ccall->auth_way_info_len = *out_len; 360 361 memcpy(save_out_data, out_data, out_max_len); 362 *out_len = out_max_len; 363 364 *st = rpc_s_partial_credentials; 365 } 366 } 367 RPC_DG_CCALL_RELEASE(&ccall); 368} 369 370/* 371 * C O N V _ W H O _ A R E _ Y O U _ A U T H _ M O R E 372 * 373 * This routine is used, in conjunction with the conv_who_are_you_auth() 374 * operation, for retrieving oversized PACs. In the event that a client's 375 * credentials are too large to fit within a single DG packet, the server 376 * can retrieve the PAC, packet by packet, by repeated calls on this 377 * operation. 378 * 379 * Note that because the "conv" interface is serviced directly by the 380 * the DG protocol (as opposed to being handled by a call executor thread), 381 * there is no additional client overhead with retrieving the PAC by 382 * multiple single-packet calls, rather than a single multiple-packet call. 383 * The small amount of overhead induced on the server side is more than 384 * compensated for by being able to avoid adding flow-control/windowing 385 * to the DG protocol's internal handling of the conv interface. 386 * 387 * Logically, this call returns 388 * 389 * client_credentials[index ... (index+out_max_len-1)] 390 */ 391 392PRIVATE void conv_who_are_you_auth_more (h, actuid, boot_time, index, 393 out_max_len, out_data, out_len, st) 394handle_t h ATTRIBUTE_UNUSED; /* not really */ 395idl_uuid_t *actuid; 396unsigned32 boot_time; 397signed32 index; 398signed32 out_max_len; 399ndr_byte *out_data; 400signed32 *out_len; 401unsigned32 *st; 402{ 403 rpc_dg_ccall_p_t ccall; 404 rpc_dg_auth_epv_p_t epv ATTRIBUTE_UNUSED; 405 406 RPC_LOCK_ASSERT(0); 407 408 if (! conv_common(actuid, boot_time, &ccall, st)) 409 { 410 return; 411 } 412 413 if ((unsigned32)(index + out_max_len) >= ccall->auth_way_info_len) 414 { 415 *out_len = ccall->auth_way_info_len - index; 416 *st = rpc_s_ok; 417 } 418 else 419 { 420 *out_len = out_max_len; 421 *st = rpc_s_partial_credentials; 422 } 423 424 memcpy(out_data, ccall->auth_way_info + index, *out_len); 425 RPC_DG_CCALL_RELEASE(&ccall); 426} 427