xref: /illumos-gate/usr/src/lib/krb5/kadm5/clnt/client_principal.c (revision 6dde88b51419b99fe0aab8e56184c693945826b8)
1 /*
2  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 
7 /*
8  * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
9  *
10  *	Openvision retains the copyright to derivative works of
11  *	this source code.  Do *NOT* create a derivative of this
12  *	source code before consulting with your legal department.
13  *	Do *NOT* integrate *ANY* of this source code into another
14  *	product before consulting with your legal department.
15  *
16  *	For further information, read the top-level Openvision
17  *	copyright which is contained in the top-level MIT Kerberos
18  *	copyright.
19  *
20  * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
21  *
22  */
23 
24 
25 /*
26  * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
27  *
28  * $Header$
29  */
30 
31 #if !defined(lint) && !defined(__CODECENTER__)
32 static char *rcsid = "$Header$";
33 #endif
34 
35 #include    <rpc/rpc.h>  /* SUNWresync121 XXX */
36 #include    <kadm5/admin.h>
37 #include    <kadm5/kadm_rpc.h>
38 #ifdef HAVE_MEMORY_H
39 #include    <memory.h>
40 #endif
41 #include    <errno.h>
42 #include    "client_internal.h"
43 
44 #ifdef DEBUG /* SUNWresync14 XXX */
45 #define eret() {clnt_perror(handle->clnt, "null ret"); return KADM5_RPC_ERROR;}
46 #else
47 #define eret() return KADM5_RPC_ERROR
48 #endif
49 
50 kadm5_ret_t
51 kadm5_create_principal(void *server_handle,
52 			    kadm5_principal_ent_t princ, long mask,
53 			    char *pw)
54 {
55     generic_ret		*r;
56     cprinc_arg		arg;
57     kadm5_server_handle_t handle = server_handle;
58 
59     CHECK_HANDLE(server_handle);
60 
61     memset(&arg, 0, sizeof(arg));
62     arg.mask = mask;
63     arg.passwd = pw;
64     arg.api_version = handle->api_version;
65 
66     if(princ == NULL)
67 	return EINVAL;
68 
69     if (handle->api_version == KADM5_API_VERSION_1) {
70        memcpy(&arg.rec, princ, sizeof(kadm5_principal_ent_rec_v1));
71     } else {
72        memcpy(&arg.rec, princ, sizeof(kadm5_principal_ent_rec));
73     }
74     if (handle->api_version == KADM5_API_VERSION_1) {
75 	 /*
76 	  * hack hack cough cough.
77 	  * krb5_unparse name dumps core if we pass it in garbage
78 	  * or null. So, since the client is not allowed to set mod_name
79 	  * anyway, we just fill it in with a dummy principal. The server of
80 	  * course ignores this.
81 	  */
82 	/* krb5_parse_name(handle->context, "bogus/bogus", &arg.rec.mod_name); */
83 	 arg.rec.mod_name = NULL;
84     } else
85 	 arg.rec.mod_name = NULL;
86 
87     if(!(mask & KADM5_POLICY))
88 	arg.rec.policy = NULL;
89     if (! (mask & KADM5_KEY_DATA)) {
90 	 arg.rec.n_key_data = 0;
91 	 arg.rec.key_data = NULL;
92     }
93     if (! (mask & KADM5_TL_DATA)) {
94 	 arg.rec.n_tl_data = 0;
95 	 arg.rec.tl_data = NULL;
96     }
97 
98     r = create_principal_2(&arg, handle->clnt);
99 
100     if (handle->api_version == KADM5_API_VERSION_1)
101 	 krb5_free_principal(handle->context, arg.rec.mod_name);
102 
103     if(r == NULL)
104 	eret();
105     return r->code;
106 }
107 
108 kadm5_ret_t
109 kadm5_create_principal_3(void *server_handle,
110 			 kadm5_principal_ent_t princ, long mask,
111 			 int n_ks_tuple,
112 			 krb5_key_salt_tuple *ks_tuple,
113 			 char *pw)
114 {
115     generic_ret		*r;
116     cprinc3_arg		arg;
117     kadm5_server_handle_t handle = server_handle;
118 
119     CHECK_HANDLE(server_handle);
120 
121     memset(&arg, 0, sizeof(arg));
122     arg.mask = mask;
123     arg.passwd = pw;
124     arg.api_version = handle->api_version;
125     arg.n_ks_tuple = n_ks_tuple;
126     arg.ks_tuple = ks_tuple;
127 
128     if(princ == NULL)
129 	return EINVAL;
130 
131     if (handle->api_version == KADM5_API_VERSION_1) {
132        memcpy(&arg.rec, princ, sizeof(kadm5_principal_ent_rec_v1));
133     } else {
134        memcpy(&arg.rec, princ, sizeof(kadm5_principal_ent_rec));
135     }
136     if (handle->api_version == KADM5_API_VERSION_1) {
137 	 /*
138 	  * hack hack cough cough.
139 	  * krb5_unparse name dumps core if we pass it in garbage
140 	  * or null. So, since the client is not allowed to set mod_name
141 	  * anyway, we just fill it in with a dummy principal. The server of
142 	  * course ignores this.
143 	  */
144 	 krb5_parse_name(handle->context, "bogus/bogus", &arg.rec.mod_name);
145     } else
146 	 arg.rec.mod_name = NULL;
147 
148     if(!(mask & KADM5_POLICY))
149 	arg.rec.policy = NULL;
150     if (! (mask & KADM5_KEY_DATA)) {
151 	 arg.rec.n_key_data = 0;
152 	 arg.rec.key_data = NULL;
153     }
154     if (! (mask & KADM5_TL_DATA)) {
155 	 arg.rec.n_tl_data = 0;
156 	 arg.rec.tl_data = NULL;
157     }
158 
159     r = create_principal3_2(&arg, handle->clnt);
160 
161     if (handle->api_version == KADM5_API_VERSION_1)
162 	 krb5_free_principal(handle->context, arg.rec.mod_name);
163 
164     if(r == NULL)
165 	eret();
166     return r->code;
167 }
168 
169 kadm5_ret_t
170 kadm5_delete_principal(void *server_handle, krb5_principal principal)
171 {
172     dprinc_arg		arg;
173     generic_ret		*r;
174     kadm5_server_handle_t handle = server_handle;
175 
176     CHECK_HANDLE(server_handle);
177 
178     if(principal == NULL)
179 	return EINVAL;
180     arg.princ = principal;
181     arg.api_version = handle->api_version;
182     r = delete_principal_2(&arg, handle->clnt);
183     if(r == NULL)
184 	eret();
185     return r->code;
186 }
187 
188 kadm5_ret_t
189 kadm5_modify_principal(void *server_handle,
190 			    kadm5_principal_ent_t princ, long mask)
191 {
192     mprinc_arg		arg;
193     generic_ret		*r;
194     kadm5_server_handle_t handle = server_handle;
195 
196     CHECK_HANDLE(server_handle);
197 
198     memset(&arg, 0, sizeof(arg));
199     arg.mask = mask;
200     arg.api_version = handle->api_version;
201     /*
202      * cough cough gag gag
203      * see comment in create_principal.
204      */
205     if(princ == NULL)
206 	return EINVAL;
207     if (handle->api_version == KADM5_API_VERSION_1) {
208         memcpy(&arg.rec, princ, sizeof(kadm5_principal_ent_rec_v1));
209     } else {
210         memcpy(&arg.rec, princ, sizeof(kadm5_principal_ent_rec));
211     }
212     if(!(mask & KADM5_POLICY))
213 	arg.rec.policy = NULL;
214     if (! (mask & KADM5_KEY_DATA)) {
215 	 arg.rec.n_key_data = 0;
216 	 arg.rec.key_data = NULL;
217     }
218     if (! (mask & KADM5_TL_DATA)) {
219 	 arg.rec.n_tl_data = 0;
220 	 arg.rec.tl_data = NULL;
221     }
222 
223     if (handle->api_version == KADM5_API_VERSION_1) {
224 	 /*
225 	  * See comment in create_principal
226 	  */
227 	 krb5_parse_name(handle->context, "bogus/bogus", &arg.rec.mod_name);
228     } else
229 	 arg.rec.mod_name = NULL;
230 
231     r = modify_principal_2(&arg, handle->clnt);
232 
233     if (handle->api_version == KADM5_API_VERSION_1)
234 	 krb5_free_principal(handle->context, arg.rec.mod_name);
235 
236     if(r == NULL)
237 	eret();
238     return r->code;
239 }
240 
241 kadm5_ret_t
242 kadm5_get_principal(void *server_handle,
243 		    krb5_principal princ, kadm5_principal_ent_t ent,
244 		    long mask)
245 {
246     gprinc_arg	arg;
247     gprinc_ret	*r;
248     kadm5_server_handle_t handle = server_handle;
249 
250     CHECK_HANDLE(server_handle);
251 
252     if(princ == NULL)
253 	return EINVAL;
254     arg.princ = princ;
255     if (handle->api_version == KADM5_API_VERSION_1)
256        arg.mask = KADM5_PRINCIPAL_NORMAL_MASK;
257     else
258        arg.mask = mask;
259     arg.api_version = handle->api_version;
260     r = get_principal_2(&arg, handle->clnt);
261     if(r == NULL)
262 	eret();
263     if (handle->api_version == KADM5_API_VERSION_1) {
264 	 kadm5_principal_ent_t_v1 *entp;
265 
266 	 entp = (kadm5_principal_ent_t_v1 *) ent;
267 	 if (r->code == 0) {
268 	      if (!(*entp = (kadm5_principal_ent_t_v1)
269 		    malloc(sizeof(kadm5_principal_ent_rec_v1))))
270 		   return ENOMEM;
271 	      /* this memcpy works because the v1 structure is an initial
272 		 subset of the v2 struct.  C guarantees that this will
273 		 result in the same layout in memory */
274 	      memcpy(*entp, &r->rec, sizeof(**entp));
275 	 } else {
276 	    *entp = NULL;
277 	 }
278     } else {
279 	 if (r->code == 0)
280 	      memcpy(ent, &r->rec, sizeof(r->rec));
281     }
282 
283     return r->code;
284 }
285 
286 kadm5_ret_t
287 kadm5_get_principals(void *server_handle,
288 			  char *exp, char ***princs, int *count)
289 {
290     gprincs_arg	arg;
291     gprincs_ret	*r;
292     kadm5_server_handle_t handle = server_handle;
293 
294     CHECK_HANDLE(server_handle);
295 
296     if(princs == NULL || count == NULL)
297 	return EINVAL;
298     arg.exp = exp;
299     arg.api_version = handle->api_version;
300     r = get_princs_2(&arg, handle->clnt);
301     if(r == NULL)
302 	eret();
303     if(r->code == 0) {
304 	 *count = r->count;
305 	 *princs = r->princs;
306     } else {
307 	 *count = 0;
308 	 *princs = NULL;
309     }
310 
311     return r->code;
312 }
313 
314 kadm5_ret_t
315 kadm5_rename_principal(void *server_handle,
316 			    krb5_principal source, krb5_principal dest)
317 {
318     rprinc_arg		arg;
319     generic_ret		*r;
320     kadm5_server_handle_t handle = server_handle;
321 
322     CHECK_HANDLE(server_handle);
323 
324     arg.src = source;
325     arg.dest = dest;
326     arg.api_version = handle->api_version;
327     if (source == NULL || dest == NULL)
328 	return EINVAL;
329     r = rename_principal_2(&arg, handle->clnt);
330     if(r == NULL)
331 	eret();
332     return r->code;
333 }
334 
335 kadm5_ret_t
336 kadm5_chpass_principal(void *server_handle,
337 			    krb5_principal princ, char *password)
338 {
339     chpass_arg		arg;
340     generic_ret		*r;
341     kadm5_server_handle_t handle = server_handle;
342 
343     CHECK_HANDLE(server_handle);
344 
345     arg.princ = princ;
346     arg.pass = password;
347     arg.api_version = handle->api_version;
348 
349     if(princ == NULL)
350 	return EINVAL;
351     r = chpass_principal_2(&arg, handle->clnt);
352     if(r == NULL)
353 	eret();
354     return r->code;
355 }
356 
357 kadm5_ret_t
358 kadm5_chpass_principal_3(void *server_handle,
359 			 krb5_principal princ, krb5_boolean keepold,
360 			 int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
361 			 char *password)
362 {
363     chpass3_arg		arg;
364     generic_ret		*r;
365     kadm5_server_handle_t handle = server_handle;
366 
367     CHECK_HANDLE(server_handle);
368 
369     arg.princ = princ;
370     arg.pass = password;
371     arg.api_version = handle->api_version;
372     arg.keepold = keepold;
373     arg.n_ks_tuple = n_ks_tuple;
374     arg.ks_tuple = ks_tuple;
375 
376     if(princ == NULL)
377 	return EINVAL;
378     r = chpass_principal3_2(&arg, handle->clnt);
379     if(r == NULL)
380 	eret();
381     return r->code;
382 }
383 
384 kadm5_ret_t
385 kadm5_setv4key_principal(void *server_handle,
386 			 krb5_principal princ,
387 			 krb5_keyblock *keyblock)
388 {
389     setv4key_arg	arg;
390     generic_ret		*r;
391     kadm5_server_handle_t handle = server_handle;
392 
393     CHECK_HANDLE(server_handle);
394 
395     arg.princ = princ;
396     arg.keyblock = keyblock;
397     arg.api_version = handle->api_version;
398 
399     if(princ == NULL || keyblock == NULL)
400 	return EINVAL;
401     r = setv4key_principal_2(&arg, handle->clnt);
402     if(r == NULL)
403 	eret();
404     return r->code;
405 }
406 
407 kadm5_ret_t
408 kadm5_setkey_principal(void *server_handle,
409 		       krb5_principal princ,
410 		       krb5_keyblock *keyblocks,
411 		       int n_keys)
412 {
413     setkey_arg		arg;
414     generic_ret		*r;
415     kadm5_server_handle_t handle = server_handle;
416 
417     CHECK_HANDLE(server_handle);
418 
419     arg.princ = princ;
420     arg.keyblocks = keyblocks;
421     arg.n_keys = n_keys;
422     arg.api_version = handle->api_version;
423 
424     if(princ == NULL || keyblocks == NULL)
425 	return EINVAL;
426     r = setkey_principal_2(&arg, handle->clnt);
427     if(r == NULL)
428 	eret();
429     return r->code;
430 }
431 
432 kadm5_ret_t
433 kadm5_setkey_principal_3(void *server_handle,
434 			 krb5_principal princ,
435 			 krb5_boolean keepold, int n_ks_tuple,
436 			 krb5_key_salt_tuple *ks_tuple,
437 			 krb5_keyblock *keyblocks,
438 			 int n_keys)
439 {
440     setkey3_arg		arg;
441     generic_ret		*r;
442     kadm5_server_handle_t handle = server_handle;
443 
444     CHECK_HANDLE(server_handle);
445 
446     arg.princ = princ;
447     arg.keyblocks = keyblocks;
448     arg.n_keys = n_keys;
449     arg.api_version = handle->api_version;
450     arg.keepold = keepold;
451     arg.n_ks_tuple = n_ks_tuple;
452     arg.ks_tuple = ks_tuple;
453 
454     if(princ == NULL || keyblocks == NULL)
455 	return EINVAL;
456     r = setkey_principal3_2(&arg, handle->clnt);
457     if(r == NULL)
458 	eret();
459     return r->code;
460 }
461 
462 /*
463  * Solaris Kerberos:
464  * This routine implements just the "old" randkey_principal code.
465  * The code in the kadmin client sometimes needs to call this
466  * directly when the kadm5_randkey_principal_3 call fails.
467  *
468  * The kadmin client utility uses a specific set of key/salt tuples,
469  * so the standard fallback in kadm5_randkey_principal (see below)
470  * will not work because it would result in kadm5_randkey_principal_3
471  * being called twice - once with the specific key/salts specified by
472  * kadmin and once with the NULL set (used to indicate that the server
473  * should use the full set of supported enctypes).  Making this
474  * routine separate makes the code simpler and avoids making the
475  * kadm5_randkey_principal_3 twice from kadmin.
476  */
477 kadm5_ret_t
478 kadm5_randkey_principal_old(void *server_handle,
479 			krb5_principal princ,
480 			krb5_keyblock **key,
481 			int *n_keys)
482 {
483 	chrand_arg		arg;
484 	chrand_ret		*r;
485 	kadm5_server_handle_t handle = server_handle;
486 	int		i, ret;
487 
488 	/* For safety */
489 	if (n_keys)
490 		*n_keys = 0;
491 	if (key)
492 		*key = NULL;
493 	CHECK_HANDLE(server_handle);
494 
495 	arg.princ = princ;
496 	arg.api_version = handle->api_version;
497 
498 	if(princ == NULL)
499 		return EINVAL;
500 	r = chrand_principal_2(&arg, handle->clnt);
501 	if (r == NULL)
502 		return KADM5_RPC_ERROR;
503 	if (handle->api_version == KADM5_API_VERSION_1) {
504 		if (key)
505 			krb5_copy_keyblock(handle->context, &r->key, key);
506 	} else if (key && (r->n_keys > 0)) {
507 		*key = (krb5_keyblock *) malloc(
508 			r->n_keys*sizeof(krb5_keyblock));
509 		if (*key == NULL)
510 			return ENOMEM;
511 		for (i = 0; i < r->n_keys; i++) {
512 			ret = krb5_copy_keyblock_contents(
513 				handle->context,
514 				&r->keys[i],
515 				&(*key)[i]);
516 			if (ret) {
517 				free(*key);
518 				*key = NULL;
519 				return ENOMEM;
520 			}
521 		}
522 		if (n_keys)
523 			*n_keys = r->n_keys;
524 	}
525 	return (r->code);
526 }
527 
528 kadm5_ret_t
529 kadm5_randkey_principal_3(void *server_handle,
530 			  krb5_principal princ,
531 			  krb5_boolean keepold, int n_ks_tuple,
532 			  krb5_key_salt_tuple *ks_tuple,
533 			  krb5_keyblock **key, int *n_keys)
534 {
535     chrand3_arg		arg;
536     chrand_ret		*r;
537     kadm5_server_handle_t handle = server_handle;
538     int			i, ret;
539 
540     /* Solaris Kerberos - For safety */
541     if (n_keys)
542 	*n_keys = 0;
543     if (key)
544 	*key = NULL;
545 
546     CHECK_HANDLE(server_handle);
547 
548     arg.princ = princ;
549     arg.api_version = handle->api_version;
550     arg.keepold = keepold;
551     arg.n_ks_tuple = n_ks_tuple;
552     arg.ks_tuple = ks_tuple;
553 
554     if(princ == NULL)
555 	return EINVAL;
556     r = chrand_principal3_2(&arg, handle->clnt);
557     if(r == NULL)
558 	eret();
559     if (handle->api_version == KADM5_API_VERSION_1) {
560 	 if (key)
561 	      krb5_copy_keyblock(handle->context, &r->key, key);
562     } else {
563 	 if (n_keys)
564 	      *n_keys = r->n_keys;
565 	 if (key) {
566 	      if(r->n_keys) {
567 		      *key = (krb5_keyblock *)
568 			      malloc(r->n_keys*sizeof(krb5_keyblock));
569 		      if (*key == NULL)
570 			      return ENOMEM;
571 		      for (i = 0; i < r->n_keys; i++) {
572 			      ret = krb5_copy_keyblock_contents(handle->context,
573 								&r->keys[i],
574 								&(*key)[i]);
575 			      if (ret) {
576 				      free(*key);
577 				      return ENOMEM;
578 			      }
579 		      }
580 	      } else *key = NULL;
581          }
582     }
583 
584     return r->code;
585 }
586 
587 kadm5_ret_t
588 kadm5_randkey_principal(void *server_handle,
589 			krb5_principal princ,
590 			krb5_keyblock **key, int *n_keys)
591 {
592 	/* Solaris Kerberos */
593 	kadm5_ret_t kret;
594 
595 	/*
596 	 * Default to trying the newest API to insure that the full
597 	 * set of enctypes is created.
598 	 */
599 	kret = kadm5_randkey_principal_3(server_handle, princ, FALSE,
600 		0, NULL, key, n_keys);
601 
602 	/*
603 	 * We will get an RPC error if the RPC call failed which
604 	 * will normally indicate that the remote procedure did not
605 	 * exist on the server, so try the older API.
606 	 */
607 	if (kret == KADM5_RPC_ERROR) {
608 		kret = kadm5_randkey_principal_old(server_handle, princ,
609 				key, n_keys);
610 	}
611 	return (kret);
612 }
613 
614 /* not supported on client side */
615 kadm5_ret_t kadm5_decrypt_key(void *server_handle,
616 			      kadm5_principal_ent_t entry, krb5_int32
617 			      ktype, krb5_int32 stype, krb5_int32
618 			      kvno, krb5_keyblock *keyblock,
619 			      krb5_keysalt *keysalt, int *kvnop)
620 {
621      return EINVAL;
622 }
623