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**      cs_s_eval.c
82**
83**  FACILITY:
84**
85**      Remote Procedure Call (RPC) evaluation setup function
86**
87**  ABSTRACT:
88**
89**      PUBLIC RPC
90**      by
91**
92*/
93
94#include <commonp.h>         /* RPC common definitions                    */
95#include <com.h>             /* RPC communication definitons              */
96#include <comp.h>            /* Private Communication Services            */
97#include <ns.h>              /* Private NS defs for other RPC components  */
98#include <nsp.h>             /* Private defs for Naming Service component */
99#include <nsentry.h>         /* Externals for NS Entry sub-component      */
100#include <dce/rpc.h>
101
102#include <cs_s.h>	     /* Private defs for code set interoperability */
103#include <dce/dce_cf.h>	     /* Access to the backing store library */
104
105
106/*
107**++
108**  ROUTINE NAME:           rpc_ns_import_ctx_add_eval
109**
110**  SCOPE:                  PUBLIC - declared in rpc.idl
111**
112**  DESCRIPTION:
113**
114**  Add an evaluation routine (function pointer) to a list of an import context.
115**  If the list does not exit, allocate the list first.
116**
117**  INPUTS:
118**
119**      function type	    Evaluation function type.  Currently, only types
120**			    supported are 'RPC_EVAL_TYPE_CODESETS' and
121**			    'RPC_CUSTOM_EVAL_TYPE_CODESETS'.
122**
123**      args		    Arguments to the custom evaluation routine.
124**                          For OSF supplied evaluation routine, this is NULL.
125**
126**	evaluation function
127**			    Function pointer to an evaluation routine.
128**			    Currently, only evaluation expected is code set
129**			    compatibility evaluations.
130**
131**	free function
132**			    Function pointer to a free routine.  This is
133**			    a user supplied routine, which is called when
134**			    'function type' is 'rpc_custom_eval_type_codesets'.
135**
136**
137**
138**  INPUT/OUPUTS:
139**
140**	import context	    Import context which is used for finding a server.
141**			    This is allocated by the previous
142**			    rpc_ns_binding_import_begin() call. 'eval_routines'
143**			    (which is type rpc_ns_handle_t) will hold the
144**			    information about evaluation routines.
145**
146**  OUTPUTS:
147**
148**      status              The result of the operation. One of:
149**                              rpc_s_ok
150**				rpc_s_invalid_ns_handle
151**                              rpc_s_no_memory
152**                          Status from rpc_rgy_get_codesets()
153**
154**  IMPLICIT INPUTS:        none
155**
156**  IMPLICIT OUTPUTS:       none
157**
158**  FUNCTION VALUE:         void
159**
160**  SIDE EFFECTS:           none
161**
162**--
163*/
164
165PUBLIC
166void rpc_ns_import_ctx_add_eval
167(
168	rpc_ns_handle_t		*import_ctx,
169	unsigned32		func_type,
170	void			*args,
171	void			(*eval_func)(handle_t binding_h, void *args, void **cntx),
172	void			(*cs_free_func)(void *cntx),
173	error_status_t		*status
174)
175{
176	rpc_cs_eval_func_p_t		eval_func_rep;
177	rpc_cs_eval_list_p_t		eval_list_p;
178	rpc_import_rep_p_t		import_p;
179	rpc_lkup_rep_p_t		lookup_p;
180	unsigned_char_p_t		client_codesets_file_p;
181	rpc_codeset_mgmt_p_t		client_codeset_p;
182
183	CODING_ERROR (status);
184	RPC_NS_VERIFY_INIT();
185
186	import_p = (rpc_import_rep_p_t)*import_ctx;
187	lookup_p = (rpc_lkup_rep_p_t)import_p->lookup_context;
188
189	if (lookup_p == NULL)
190	{
191		*status = rpc_s_invalid_ns_handle;
192		return;
193	}
194
195	switch (func_type)
196	{
197	case RPC_EVAL_TYPE_CODESETS:
198	case RPC_CUSTOM_EVAL_TYPE_CODESETS:
199
200		/*
201		 * Check if import func context is already allocated
202		 */
203
204		if (lookup_p->eval_routines == NULL)	/* no list exists yet */
205		{
206			/*
207			 * Allocate the new import func context.
208			 */
209			RPC_MEM_ALLOC (
210			eval_func_rep,
211			rpc_cs_eval_func_p_t,
212			sizeof (rpc_cs_eval_func_t),
213			RPC_C_MEM_FUNC,
214			RPC_C_MEM_WAITOK);
215
216			/*
217			 * Allocate a list
218			 */
219			RPC_MEM_ALLOC (
220				eval_list_p,
221				rpc_cs_eval_list_p_t,
222				sizeof (rpc_cs_eval_list_t),
223				RPC_C_MEM_LIST,
224				RPC_C_MEM_WAITOK);
225
226			/*
227			 * set up the contents of the stack
228			 */
229			eval_list_p->type = func_type;
230			eval_list_p->eval_func = eval_func;
231			eval_list_p->cs_free_func = cs_free_func;
232			eval_list_p->cntx = NULL;
233			eval_list_p->next = NULL;
234
235			/* Get client's supported code sets */
236			rpc_rgy_get_codesets (  &client_codeset_p,
237						status );
238
239			if (*status != rpc_s_ok)
240			{
241				RPC_MEM_FREE (eval_func_rep, RPC_C_MEM_FUNC);
242				RPC_MEM_FREE (eval_list_p, RPC_C_MEM_LIST);
243				return;
244			}
245			eval_list_p->args = (void *)client_codeset_p;
246
247			/*
248			 * set the list to import func context
249			 */
250			eval_func_rep->list = eval_list_p;
251
252			eval_func_rep->num = 1;
253
254			/*
255			 * set the list into import context
256			 */
257			lookup_p->eval_routines = (rpc_ns_handle_t)eval_func_rep;
258
259		}
260		else
261		{
262
263			/*
264			 * Allocate a list
265			 */
266			RPC_MEM_ALLOC (
267				eval_list_p,
268				rpc_cs_eval_list_p_t,
269				sizeof (rpc_cs_eval_list_t),
270				RPC_C_MEM_LIST,
271				RPC_C_MEM_WAITOK);
272
273			/*
274			 * set up the contents of the stack
275			 */
276			eval_list_p->type = func_type;
277			eval_list_p->eval_func = eval_func;
278			eval_list_p->cs_free_func = cs_free_func;
279			eval_list_p->cntx = NULL;
280			eval_list_p->next = NULL;
281
282			/* Get client's supported code sets */
283			rpc_rgy_get_codesets (	&client_codeset_p,
284						status );
285
286			if (*status != rpc_s_ok)
287			{
288				RPC_MEM_FREE (eval_func_rep, RPC_C_MEM_FUNC);
289				RPC_MEM_FREE (eval_list_p, RPC_C_MEM_LIST);
290				return;
291			}
292			eval_list_p->args = (rpc_ns_handle_t *)client_codeset_p;
293
294			/*
295			 * set the stack pointer to newly allocated stack
296			 */
297			eval_func_rep = (rpc_cs_eval_func_p_t)lookup_p->eval_routines;
298			eval_func_rep->list->next = eval_list_p;
299
300			eval_func_rep->num += 1;
301		}
302		*status = rpc_s_ok;
303		return;
304
305	default:
306		;
307
308	}
309}
310
311
312/*
313**++
314**  ROUTINE NAME:           rpc_cs_eval_with_universal
315**
316**  SCOPE:                  PUBLIC - declared in rpc.idl
317**
318**  DESCRIPTION:
319**
320**  An evaluation routine to evaluate client's and server's supported
321**  code sets.  If no code sets match, Universal code set will be used
322**  for the wire communication.
323**
324**  INPUTS:
325**
326**	binding_h
327**			RPC binding_handle.
328**
329**	args 		Actually points to 'rpc_cs_codeset_i14y_data_p'
330**			data type.
331**
332**  INPUT/OUPUTS:
333**
334**	cntx 		Points to 'rpc_cs_codeset_i14y_data_p' data type,
335**			and keep track of function execution.
336**
337**  OUTPUTS: none
338**
339**  IMPLICIT INPUTS:        none
340**
341**  IMPLICIT OUTPUTS:       none
342**
343**  FUNCTION VALUE:         void
344**
345**  SIDE EFFECTS:           none
346**
347**--
348*/
349
350PUBLIC
351void rpc_cs_eval_with_universal
352(
353	handle_t		binding_h,
354	void			*args,
355	void			**cntx
356)
357{
358	rpc_cs_codeset_i14y_data_p	i14y_data_p;
359	rpc_cs_codeset_i14y_data_p	cntx_i14y_data_p;
360	rpc_cs_method_eval_p_t		method_p;
361	rpc_ns_handle_t			inq_context;
362	unsigned_char_p_t		client_codesets_file;
363	unsigned_char_p_t		ns_name_p;
364	int				i,j;
365	int				model_found;
366	int				smir_true;
367	int				cmir_true;
368	long				i_code;
369	int				i_max_bytes;
370	error_status_t			temp_status;
371
372	i14y_data_p = (rpc_cs_codeset_i14y_data_p)args;
373
374	if (i14y_data_p->cleanup)
375	{
376		cntx_i14y_data_p = (rpc_cs_codeset_i14y_data_p)*cntx;
377		cntx_i14y_data_p->status = rpc_s_ok;
378		return;
379	}
380
381	method_p = i14y_data_p->method_p;
382	if (cntx == NULL)
383	{
384			return;
385	}
386	else
387		cntx_i14y_data_p = (rpc_cs_codeset_i14y_data_p)*cntx;
388
389	/*
390	 * Get the client's supported code sets.
391	 */
392	if (method_p->client == NULL)
393	{
394		rpc_rgy_get_codesets (
395			&method_p->client,
396			&cntx_i14y_data_p->status);
397
398		if (cntx_i14y_data_p->status != rpc_s_ok)
399			return;
400	}
401
402	/*
403	** Get the server's supported code sets from NSI.
404	*/
405
406	ns_name_p = i14y_data_p->ns_name;
407
408	rpc_ns_mgmt_read_codesets (
409		rpc_c_ns_syntax_default,
410		ns_name_p,
411		&method_p->server,
412		&cntx_i14y_data_p->status);
413
414	if (cntx_i14y_data_p->status != rpc_s_ok)
415	{
416		rpc_ns_mgmt_free_codesets( &method_p->client, &temp_status);
417		return;
418	}
419
420	/*
421	 * Start evaluation
422	 */
423	if (method_p->client->codesets[0].c_set
424			== method_p->server->codesets[0].c_set)
425	{
426		/*
427		 * Both client and server are using the same code set
428		 */
429		method_p->method = RPC_EVAL_NO_CONVERSION;
430		method_p->tags.stag = method_p->client->codesets[0].c_set;
431		method_p->tags.drtag = method_p->server->codesets[0].c_set;
432	}
433	else
434	{
435		/*
436		 * We check character set compatibility first.
437		 */
438		rpc_cs_char_set_compat_check (
439			method_p->client->codesets[0].c_set,
440			method_p->server->codesets[0].c_set,
441			&cntx_i14y_data_p->status);
442
443		if (cntx_i14y_data_p->status != rpc_s_ok)
444		{
445			/*
446			 * Character set for client and server didn't match.
447			 * Mass of data loss could result, so we quit the
448			 * evaluation here.
449			 */
450			rpc_ns_mgmt_free_codesets( &method_p->server, &temp_status);
451			return;
452		}
453		else
454		{
455			smir_true = cmir_true = model_found = 0;
456
457			for (i = 1; i <= method_p->server->count; i++)
458			{
459			   if (model_found)
460				break;
461
462			   if (method_p->client->codesets[0].c_set
463				== method_p->server->codesets[i].c_set)
464			   {
465				smir_true = 1;
466				model_found = 1;
467			   }
468
469			   if (method_p->server->codesets[0].c_set
470				== method_p->client->codesets[i].c_set)
471			   {
472				cmir_true = 1;
473				model_found = 1;
474			   }
475			}
476
477			if (model_found)
478			{
479			   if (smir_true && cmir_true)
480			   {
481				/* RMIR model works */
482				method_p->method = RPC_EVAL_RMIR_MODEL;
483				method_p->tags.stag
484					= method_p->client->codesets[0].c_set;
485				method_p->tags.drtag
486				    	= method_p->server->codesets[0].c_set;
487				method_p->tags.stag_max_bytes
488				    = method_p->client->codesets[0].c_max_bytes;
489				method_p->tags.client_tag
490				    = method_p->client->codesets[0].c_set;
491				method_p->tags.client_max_bytes
492				    = method_p->client->codesets[0].c_max_bytes;
493			   }
494			   else if (smir_true)
495			   {
496				/* SMIR model */
497				method_p->method = RPC_EVAL_SMIR_MODEL;
498				method_p->tags.stag
499				    	= method_p->client->codesets[0].c_set;
500				method_p->tags.drtag
501				     	= method_p->client->codesets[0].c_set;
502				method_p->tags.stag_max_bytes
503				    = method_p->client->codesets[0].c_max_bytes;
504				method_p->tags.client_tag
505				    = method_p->client->codesets[0].c_set;
506				method_p->tags.client_max_bytes
507				    = method_p->client->codesets[0].c_max_bytes;
508			   }
509			   else
510			   {
511				/* CMIR model */
512				method_p->method = RPC_EVAL_CMIR_MODEL;
513				method_p->tags.stag
514					= method_p->server->codesets[0].c_set;
515				method_p->tags.drtag
516					= method_p->server->codesets[0].c_set;
517				method_p->tags.stag_max_bytes
518				    = method_p->server->codesets[0].c_max_bytes;
519				method_p->tags.client_tag
520				    = method_p->client->codesets[0].c_set;
521				method_p->tags.client_max_bytes
522				    = method_p->client->codesets[0].c_max_bytes;
523			   }
524			}
525			else
526			{
527				/*
528				 * We try to find the intermediate code set
529				 */
530				method_p->tags.client_tag
531				    = method_p->client->codesets[0].c_set;
532				method_p->tags.client_max_bytes
533				    = method_p->client->codesets[0].c_max_bytes;
534
535				for (i = 1; i <= method_p->client->count; i++)
536				{
537				   if (model_found)
538					break;
539			  	   for (j = 1; j <= method_p->server->count; j++)
540					{
541					   if (method_p->client->codesets[i].c_set
542						== method_p->server->codesets[j].c_set)
543					   {
544						i_code = method_p->client->codesets[i].c_set;
545						i_max_bytes = method_p->client->codesets[i].c_max_bytes;
546						method_p->tags.stag_max_bytes
547						   = method_p->client->codesets[i].c_max_bytes;
548						model_found = 1;
549						   break;
550				    	    }
551					}
552				}
553				if (model_found)
554				{
555					method_p->method = RPC_EVAL_INTERMEDIATE_MODEL;
556					method_p->tags.stag = i_code;
557					method_p->tags.drtag = i_code;
558			   	}
559				else
560				{
561					/*
562					 * We use UNIVERSAL code set
563					 */
564					method_p->method = RPC_EVAL_UNIVERSAL_MODEL;
565					method_p->tags.stag = UCS2_L2;
566					method_p->tags.drtag = UCS2_L2;
567					method_p->tags.client_tag
568				    	   = method_p->client->codesets[0].c_set;
569					method_p->tags.client_max_bytes
570					    = method_p->client->codesets[0].c_max_bytes;
571			    		rpc_rgy_get_max_bytes (
572						UCS2_L2,
573						&method_p->tags.stag_max_bytes,
574						&cntx_i14y_data_p->status
575					);
576					if (cntx_i14y_data_p->status != rpc_s_ok)
577					{
578						rpc_ns_mgmt_free_codesets( &method_p->server, &temp_status);
579						return;
580					}
581			   	}
582			}
583		}
584	}
585
586	method_p->fixed = ndr_true;
587	cntx_i14y_data_p->status = rpc_s_ok;
588	rpc_ns_mgmt_free_codesets( &method_p->server, &temp_status);
589	return;
590}
591
592
593/*
594**++
595**  ROUTINE NAME:           rpc_cs_eval_without_universal
596**
597**  SCOPE:                  PUBLIC - declared in rpc.idl
598**
599**  DESCRIPTION:
600**
601**  An evaluation routine to evaluate client's and server's supported
602**  code sets.  If no code sets match it fails.  Universal code set will
603**  not be used for the wire communication.
604**
605**  INPUTS:
606**
607**	binding_h
608**			RPC binding_handle.
609**
610**	args 		Actually points to 'rpc_cs_codeset_i14y_data_p'
611**			data type.
612**
613**  INPUT/OUPUTS:
614**
615**	cntx 		Points to 'rpc_cs_codeset_i14y_data_p' data type,
616**			and keep track of function execution.
617**
618**  OUTPUTS: none
619**
620**  IMPLICIT INPUTS:        none
621**
622**  IMPLICIT OUTPUTS:       none
623**
624**  FUNCTION VALUE:         void
625**
626**  SIDE EFFECTS:           none
627**
628**--
629*/
630
631PUBLIC
632void rpc_cs_eval_without_universal
633(
634	handle_t		binding_h,
635	void			*args,
636	void			**cntx
637)
638{
639	rpc_cs_codeset_i14y_data_p	i14y_data_p;
640	rpc_cs_codeset_i14y_data_p	cntx_i14y_data_p;
641	rpc_cs_method_eval_p_t		method_p;
642	rpc_ns_handle_t			inq_context;
643	unsigned_char_p_t		ns_name_p;
644	unsigned_char_p_t		client_codesets_file;
645	int				i,j;
646	int				model_found;
647	int				smir_true;
648	int				cmir_true;
649	long				i_code;
650	int				i_max_bytes;
651	error_status_t			temp_status;
652
653	i14y_data_p = (rpc_cs_codeset_i14y_data_p)args;
654
655	if (i14y_data_p->cleanup)
656	{
657		cntx_i14y_data_p = (rpc_cs_codeset_i14y_data_p)*cntx;
658		cntx_i14y_data_p->status = rpc_s_ok;
659		return;
660	}
661
662	method_p = i14y_data_p->method_p;
663	if (cntx == NULL)
664	{
665		return;
666	}
667	else
668		cntx_i14y_data_p = (rpc_cs_codeset_i14y_data_p)*cntx;
669
670	/*
671	 * Get the client's supported code sets if it is not set.
672	method_p->client = (rpc_codeset_mgmt_p_t)i14y_data_p->args;
673	 */
674	if (method_p->client == NULL)
675	{
676		rpc_rgy_get_codesets (
677			&method_p->client,
678			&cntx_i14y_data_p->status);
679
680		if (cntx_i14y_data_p->status != rpc_s_ok)
681			return;
682	}
683
684	/*
685	** Get the server's supported code sets from NSI.
686	*/
687
688	ns_name_p = i14y_data_p->ns_name;
689
690	rpc_ns_mgmt_read_codesets (
691		rpc_c_ns_syntax_default,
692		ns_name_p,
693		&method_p->server,
694		&cntx_i14y_data_p->status);
695
696	if (cntx_i14y_data_p->status != rpc_s_ok)
697	{
698		rpc_ns_mgmt_free_codesets( &method_p->client, &temp_status);
699		return;
700	}
701
702	/*
703	 * Start evaluation
704	 */
705	if (method_p->client->codesets[0].c_set
706			== method_p->server->codesets[0].c_set)
707	{
708		/*
709		 * Both client and server are using the same code set
710		 */
711		method_p->method = RPC_EVAL_NO_CONVERSION;
712		method_p->tags.stag = method_p->client->codesets[0].c_set;
713		method_p->tags.drtag = method_p->server->codesets[0].c_set;
714	}
715	else
716	{
717		/*
718		 * We check character set compatibility first.
719		 */
720		rpc_cs_char_set_compat_check (
721			method_p->client->codesets[0].c_set,
722			method_p->server->codesets[0].c_set,
723			&cntx_i14y_data_p->status);
724
725		if (cntx_i14y_data_p->status != rpc_s_ok)
726		{
727			/*
728			 * Character set for client and server didn't match.
729			 * Mass of data loss could result, so we quit the
730			 * evaluation here.
731			 */
732			rpc_ns_mgmt_free_codesets( &method_p->server, &temp_status);
733			return;
734		}
735		else
736		{
737			smir_true = cmir_true = model_found = 0;
738
739			for (i = 1; i <= method_p->server->count; i++)
740			{
741			   if (model_found)
742				break;
743
744			   if (method_p->client->codesets[0].c_set
745				== method_p->server->codesets[i].c_set)
746			   {
747				smir_true = 1;
748				model_found = 1;
749			   }
750
751			   if (method_p->server->codesets[0].c_set
752				== method_p->client->codesets[i].c_set)
753			   {
754				cmir_true = 1;
755				model_found = 1;
756			   }
757			}
758
759			if (model_found)
760			{
761			   if (smir_true && cmir_true)
762			   {
763				/* RMIR model works */
764				method_p->method = RPC_EVAL_RMIR_MODEL;
765				method_p->tags.stag = method_p->client->codesets[0].c_set;
766				method_p->tags.drtag = method_p->server->codesets[0].c_set;
767				method_p->tags.stag_max_bytes
768				    = method_p->client->codesets[0].c_max_bytes;
769				method_p->tags.client_tag
770				    = method_p->client->codesets[0].c_set;
771				method_p->tags.client_max_bytes
772				    = method_p->client->codesets[0].c_max_bytes;
773			   }
774			   else if (smir_true)
775			   {
776				/* SMIR model */
777				method_p->method = RPC_EVAL_SMIR_MODEL;
778				method_p->tags.stag = method_p->client->codesets[0].c_set;
779				method_p->tags.drtag = method_p->client->codesets[0].c_set;
780				method_p->tags.stag_max_bytes
781				    = method_p->client->codesets[0].c_max_bytes;
782				method_p->tags.client_tag
783				    = method_p->client->codesets[0].c_set;
784				method_p->tags.client_max_bytes
785				    = method_p->client->codesets[0].c_max_bytes;
786			   }
787			   else
788			   {
789				/* CMIR model */
790				method_p->method = RPC_EVAL_CMIR_MODEL;
791				method_p->tags.stag = method_p->server->codesets[0].c_set;
792				method_p->tags.drtag = method_p->server->codesets[0].c_set;
793				method_p->tags.stag_max_bytes
794				    = method_p->server->codesets[0].c_max_bytes;
795				method_p->tags.client_tag
796				    = method_p->client->codesets[0].c_set;
797				method_p->tags.client_max_bytes
798				    = method_p->client->codesets[0].c_max_bytes;
799			   }
800			}
801			else
802			{
803			   /*
804			    * We try to find intermediate code set
805			    */
806			   method_p->tags.client_tag
807				= method_p->client->codesets[0].c_set;
808			   method_p->tags.client_max_bytes
809				= method_p->client->codesets[0].c_max_bytes;
810
811			   for (i = 1; i <= method_p->client->count; i++)
812			   {
813			   	if (model_found)
814					break;
815				for (j = 1; j <= method_p->server->count; j++)
816			 	{
817				   if (method_p->client->codesets[i].c_set
818				   	== method_p->server->codesets[j].c_set)
819				   {
820				   	i_code = method_p->client->codesets[i].c_set;
821					i_max_bytes = method_p->client->codesets[i].c_max_bytes;
822
823					method_p->tags.stag_max_bytes
824					    = method_p->client->codesets[i].c_max_bytes;
825				 	model_found = 1;
826				 	break;
827				   }
828				}
829			   }
830			   if (model_found)
831			   {
832				method_p->method
833					= RPC_EVAL_INTERMEDIATE_MODEL;
834				method_p->tags.stag = i_code;
835				method_p->tags.drtag = i_code;
836			   }
837			   else
838			   {
839				/*
840				 * We do not use UNIVERSAL code set
841				 */
842				cntx_i14y_data_p->status
843						= rpc_s_ss_no_compat_codeset;
844				rpc_ns_mgmt_free_codesets( &method_p->server, &temp_status);
845				return;
846			   }
847			}
848		}
849	}
850
851	method_p->fixed = ndr_true;
852	cntx_i14y_data_p->status = rpc_s_ok;
853	rpc_ns_mgmt_free_codesets( &method_p->server, &temp_status);
854	return;
855}
856
857
858/*
859**++
860**  ROUTINE NAME:           rpc_cs_char_set_compat_check
861**
862**  SCOPE:                  PUBLIC - declared in rpc.idl
863**
864**  DESCRIPTION:
865**
866**  Evaluate the character set compatibility between client and server.
867**  Character set matching logic prevents the massive data loss when client
868**  and server are connected.
869**
870**  INPUTS:
871**
872**	client_codeset 	    OSF code set registry value for client's current
873**			    code set.
874**
875**	server_codeset 	    OSF code set registry value for server's current
876**			    code set.
877**
878**  INPUT/OUPUTS:	    none
879**
880**  OUTPUTS:
881**
882**      status              The result of the operation. One of:
883**                              rpc_s_ok
884**                              rpc_s_ss_no_compat_charsets
885**                          Status from dce_cs_loc_to_rgy()
886**
887**  IMPLICIT INPUTS:        none
888**
889**  IMPLICIT OUTPUTS:       none
890**
891**  FUNCTION VALUE:         void
892**
893**  SIDE EFFECTS:           none
894**
895**--
896*/
897
898PUBLIC
899void rpc_cs_char_set_compat_check
900(
901	unsigned32		client_codeset,
902	unsigned32		server_codeset,
903	error_status_t		*status
904)
905{
906	unsigned_char_t	*client_code_set_name;
907	unsigned16	client_char_sets_number;
908	unsigned16	*client_char_sets_value;
909	unsigned_char_t	*server_code_set_name;
910	unsigned16	server_char_sets_number;
911	unsigned16	*server_char_sets_value;
912
913	dce_cs_rgy_to_loc (
914		client_codeset,
915		&client_code_set_name,
916		&client_char_sets_number,
917		&client_char_sets_value,
918		status );
919
920	if (*status != dce_cs_c_ok)
921		return;
922
923	dce_cs_rgy_to_loc (
924		server_codeset,
925		&server_code_set_name,
926		&server_char_sets_number,
927		&server_char_sets_value,
928		status );
929
930	if (*status != dce_cs_c_ok)
931		return;
932
933	if (client_char_sets_number == 1 && server_char_sets_number == 1)
934	{
935		if (*client_char_sets_value == *server_char_sets_value)
936			*status = rpc_s_ok;
937		else
938			*status = rpc_s_ss_no_compat_charsets;
939	}
940	else
941	{
942		int		match = 0;
943		unsigned16	server_number_save;
944		unsigned16	*server_value_save;
945
946		server_number_save = server_char_sets_number;
947		server_value_save  = server_char_sets_value;
948
949		while (client_char_sets_number--)
950		{
951			while (server_char_sets_number--)
952			{
953				if (*client_char_sets_value
954						== *server_char_sets_value++)
955					match++;
956			}
957			server_char_sets_number = server_number_save;
958			server_char_sets_value  = server_value_save;
959			client_char_sets_value++;
960		}
961		if (match >= 2)
962			*status = rpc_s_ok;
963		else
964			*status = rpc_s_ss_no_compat_charsets;
965	}
966
967	return;
968}
969
970
971/*
972**++
973**  ROUTINE NAME:           rpc_cs_binding_set_method
974**
975**  SCOPE:                  PRIVATE - declared in cs_s.h
976**
977**  DESCRIPTION:
978**
979**  An evaluation routine to evaluate client's and server's supported
980**  code sets.  If no code sets match, Universal code set will be used
981**  for the wire communication.
982**
983**  INPUTS:
984**	method_p	   pointer to the method structure.
985**
986**
987**  INPUT/OUPUTS:
988**
989**	h 		    rpc binding handle.  rpc_binding_rep_t will be
990**			    modified to rpc_binding_eval_t data structure.
991**
992**  OUTPUTS:
993**
994**      status              The result of the operation. One of:
995**                              rpc_s_ok
996**                              rpc_s_no_memory
997**
998**  IMPLICIT INPUTS:        none
999**
1000**  IMPLICIT OUTPUTS:       none
1001**
1002**  FUNCTION VALUE:         void
1003**
1004**  SIDE EFFECTS:           none
1005**
1006**--
1007*/
1008PRIVATE
1009void rpc_cs_binding_set_method
1010(
1011	rpc_binding_handle_t		*h,
1012	rpc_cs_method_eval_p_t		method_p,
1013	error_status_t			*status
1014)
1015{
1016	rpc_cs_method_eval_p_t  bind_method;
1017	rpc_binding_rep_p_t	bind_eval_p;
1018
1019	bind_eval_p = (rpc_binding_rep_p_t)*h;
1020	bind_method = &bind_eval_p->cs_eval.tagged_union.method_key;
1021
1022	bind_eval_p->cs_eval.key = RPC_CS_EVAL_METHOD;
1023	bind_method->method = method_p->method;
1024	bind_method->tags.stag = method_p->tags.stag;
1025	bind_method->tags.drtag = method_p->tags.drtag;
1026	bind_method->tags.stag_max_bytes = method_p->tags.stag_max_bytes;
1027	bind_method->tags.client_tag = method_p->tags.client_tag;
1028	bind_method->tags.client_max_bytes = method_p->tags.client_max_bytes;
1029	bind_method->fixed = method_p->fixed;
1030	bind_method->cs_stub_eval_func = NULL;
1031	bind_method->tags.type_handle = NULL;
1032	bind_method->server = method_p->server;
1033	bind_method->client = method_p->client;
1034
1035	bind_eval_p->extended_bind_flag = RPC_C_BH_EXTENDED_CODESETS;
1036        *status = rpc_s_ok;
1037        return;
1038}
1039
1040
1041/*
1042**++
1043**  ROUTINE NAME:           rpc_cs_binding_set_tags
1044**
1045**  SCOPE:                  PUBLIC - declared in rpc.idl
1046**
1047**  DESCRIPTION:
1048**
1049**  An evaluation routine to evaluate client's and server's supported
1050**  code sets.  If no code sets match, Universal code set will be used
1051**  for the wire communication.
1052**
1053**  INPUTS:
1054**	stag		   sending tag
1055**
1056**	drtag		   desired receving tag
1057**
1058**  INPUT/OUPUTS:
1059**
1060**	h 		    rpc binding handle.  rpc_binding_rep_t will be
1061**			    modified to rpc_binding_eval_t data structure.
1062**
1063**  OUTPUTS:
1064**
1065**      status              The result of the operation. One of:
1066**                              rpc_s_ok
1067**                          Status from rpc_rgy_get_codesets()
1068**
1069**  IMPLICIT INPUTS:        none
1070**
1071**  IMPLICIT OUTPUTS:       none
1072**
1073**  FUNCTION VALUE:         void
1074**
1075**  SIDE EFFECTS:           none
1076**
1077**--
1078*/
1079
1080PUBLIC
1081void rpc_cs_binding_set_tags
1082(
1083	rpc_binding_handle_t		*h,
1084	unsigned32			stag,
1085	unsigned32			drtag,
1086	unsigned16			stag_max_bytes,
1087	error_status_t			*status
1088)
1089{
1090	rpc_cs_tags_eval_p_t	bind_tags;
1091	rpc_binding_rep_p_t	bind_eval_p;
1092	rpc_codeset_mgmt_p_t	client;
1093
1094	bind_eval_p = (rpc_binding_rep_p_t)*h;
1095	bind_tags = &bind_eval_p->cs_eval.tagged_union.tags_key;
1096
1097	bind_eval_p->cs_eval.key = RPC_CS_EVAL_TAGS;
1098	bind_tags->stag = stag;
1099	bind_tags->drtag = drtag;
1100	if (stag_max_bytes != 0)
1101		bind_tags->stag_max_bytes = stag_max_bytes;
1102	else
1103		bind_tags->stag_max_bytes = 0;
1104	/*
1105	 * Get the client's supported code sets
1106	 */
1107	rpc_rgy_get_codesets (
1108		&client,
1109		status );
1110
1111	if (*status != rpc_s_ok)
1112		return;
1113
1114	bind_tags->client_tag = client->codesets[0].c_set;
1115	bind_tags->client_max_bytes = client->codesets[0].c_max_bytes;
1116
1117	bind_tags->type_handle = NULL;
1118
1119	bind_eval_p->extended_bind_flag = RPC_C_BH_EXTENDED_CODESETS;
1120
1121        *status = rpc_s_ok;
1122        return;
1123}
1124
1125
1126/*
1127**++
1128**  ROUTINE NAME:           rpc_cs_binding_set_eval
1129**
1130**  SCOPE:                  PUBLIC - declared in rpc.idl
1131**
1132**  DESCRIPTION:
1133**
1134**  Add in-stub evaluation routine to a binding handle.
1135**  When this method is used, every single RPC call will perform code set
1136**  compatibility evaluation, which can be a big impact to RPC call performance.
1137**
1138**  INPUTS:
1139**	cs_stub_eval_func   pointer to an in-stub evaluation routine.
1140**
1141**  INPUT/OUPUTS:
1142**
1143**	h 		    rpc binding handle.  rpc_binding_rep_t will be
1144**			    modified to rpc_binding_eval_t data structure.
1145**
1146**  OUTPUTS:
1147**
1148**      status              The result of the operation. One of:
1149**                              rpc_s_ok
1150**
1151**  IMPLICIT INPUTS:        none
1152**
1153**  IMPLICIT OUTPUTS:       none
1154**
1155**  FUNCTION VALUE:         void
1156**
1157**  SIDE EFFECTS:           none
1158**
1159**--
1160*/
1161
1162PUBLIC
1163void rpc_cs_binding_set_eval
1164(
1165	rpc_binding_handle_t		*h,
1166	void				(*cs_stub_eval_func)(unsigned32 *p_stag, unsigned32 *p_drtag, error_status_t *status),
1167	error_status_t			*status
1168)
1169{
1170	rpc_cs_method_eval_p_t  bind_method;
1171	rpc_binding_rep_p_t	bind_eval_p;
1172
1173	bind_eval_p = (rpc_binding_rep_p_t)*h;
1174	bind_method = &bind_eval_p->cs_eval.tagged_union.method_key;
1175
1176	bind_eval_p->cs_eval.key = RPC_CS_EVAL_METHOD;
1177	bind_method->fixed = ndr_false;
1178	bind_method->cs_stub_eval_func = cs_stub_eval_func;
1179	bind_method->tags.type_handle = NULL;
1180
1181	bind_eval_p->extended_bind_flag = RPC_C_BH_IN_STUB_EVALUATION;
1182        *status = rpc_s_ok;
1183        return;
1184}
1185