xref: /freebsd/crypto/krb5/src/kadmin/server/ipropd_svc.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
1*7f2fe78bSCy Schubert /* -*- mode: c; c-file-style: "bsd"; indent-tabs-mode: t -*- */
2*7f2fe78bSCy Schubert /*
3*7f2fe78bSCy Schubert  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
4*7f2fe78bSCy Schubert  * Use is subject to license terms.
5*7f2fe78bSCy Schubert  */
6*7f2fe78bSCy Schubert 
7*7f2fe78bSCy Schubert /* #pragma ident	"@(#)ipropd_svc.c	1.2	04/02/20 SMI" */
8*7f2fe78bSCy Schubert 
9*7f2fe78bSCy Schubert 
10*7f2fe78bSCy Schubert #include "k5-platform.h"
11*7f2fe78bSCy Schubert #include <signal.h>
12*7f2fe78bSCy Schubert #include <sys/types.h>
13*7f2fe78bSCy Schubert #include <sys/resource.h> /* rlimit */
14*7f2fe78bSCy Schubert #include <syslog.h>
15*7f2fe78bSCy Schubert 
16*7f2fe78bSCy Schubert #include <kadm5/admin.h>
17*7f2fe78bSCy Schubert #include <kadm5/kadm_rpc.h>
18*7f2fe78bSCy Schubert #include <kadm5/server_internal.h>
19*7f2fe78bSCy Schubert #include <adm_proto.h>
20*7f2fe78bSCy Schubert #include <string.h>
21*7f2fe78bSCy Schubert #include <gssapi_krb5.h>
22*7f2fe78bSCy Schubert #include <sys/socket.h>
23*7f2fe78bSCy Schubert #include <netinet/in.h>
24*7f2fe78bSCy Schubert #include <arpa/inet.h>
25*7f2fe78bSCy Schubert #include <netdb.h>
26*7f2fe78bSCy Schubert #include <kdb_log.h>
27*7f2fe78bSCy Schubert #include "auth.h"
28*7f2fe78bSCy Schubert #include "misc.h"
29*7f2fe78bSCy Schubert #include "osconf.h"
30*7f2fe78bSCy Schubert 
31*7f2fe78bSCy Schubert extern gss_name_t rqst2name(struct svc_req *rqstp);
32*7f2fe78bSCy Schubert 
33*7f2fe78bSCy Schubert extern void *global_server_handle;
34*7f2fe78bSCy Schubert extern int nofork;
35*7f2fe78bSCy Schubert extern short l_port;
36*7f2fe78bSCy Schubert extern char *kdb5_util;
37*7f2fe78bSCy Schubert extern char *kprop;
38*7f2fe78bSCy Schubert extern char *dump_file;
39*7f2fe78bSCy Schubert extern char *kprop_port;
40*7f2fe78bSCy Schubert 
41*7f2fe78bSCy Schubert static char *reply_ok_str	= "UPDATE_OK";
42*7f2fe78bSCy Schubert static char *reply_err_str	= "UPDATE_ERROR";
43*7f2fe78bSCy Schubert static char *reply_fr_str	= "UPDATE_FULL_RESYNC_NEEDED";
44*7f2fe78bSCy Schubert static char *reply_busy_str	= "UPDATE_BUSY";
45*7f2fe78bSCy Schubert static char *reply_nil_str	= "UPDATE_NIL";
46*7f2fe78bSCy Schubert static char *reply_perm_str	= "UPDATE_PERM_DENIED";
47*7f2fe78bSCy Schubert static char *reply_unknown_str	= "<UNKNOWN_CODE>";
48*7f2fe78bSCy Schubert 
49*7f2fe78bSCy Schubert #define	LOG_UNAUTH  _("Unauthorized request: %s, client=%s, service=%s, addr=%s")
50*7f2fe78bSCy Schubert #define	LOG_DONE    _("Request: %s, %s, %s, client=%s, service=%s, addr=%s")
51*7f2fe78bSCy Schubert 
52*7f2fe78bSCy Schubert #ifdef	DPRINT
53*7f2fe78bSCy Schubert #undef	DPRINT
54*7f2fe78bSCy Schubert #endif
55*7f2fe78bSCy Schubert #ifdef DEBUG
56*7f2fe78bSCy Schubert #define	DPRINT(...)				\
57*7f2fe78bSCy Schubert     do {					\
58*7f2fe78bSCy Schubert 	if (nofork) {				\
59*7f2fe78bSCy Schubert 	    fprintf(stderr, __VA_ARGS__);	\
60*7f2fe78bSCy Schubert 	    fflush(stderr);			\
61*7f2fe78bSCy Schubert 	}					\
62*7f2fe78bSCy Schubert     } while (0)
63*7f2fe78bSCy Schubert #else
64*7f2fe78bSCy Schubert #define	DPRINT(...)
65*7f2fe78bSCy Schubert #endif
66*7f2fe78bSCy Schubert 
67*7f2fe78bSCy Schubert static void
debprret(char * w,update_status_t ret,kdb_sno_t sno)68*7f2fe78bSCy Schubert debprret(char *w, update_status_t ret, kdb_sno_t sno)
69*7f2fe78bSCy Schubert {
70*7f2fe78bSCy Schubert     switch (ret) {
71*7f2fe78bSCy Schubert     case UPDATE_OK:
72*7f2fe78bSCy Schubert 	printf("%s: end (OK, sno=%u)\n",
73*7f2fe78bSCy Schubert 	       w, sno);
74*7f2fe78bSCy Schubert 	break;
75*7f2fe78bSCy Schubert     case UPDATE_ERROR:
76*7f2fe78bSCy Schubert 	printf("%s: end (ERROR)\n", w);
77*7f2fe78bSCy Schubert 	break;
78*7f2fe78bSCy Schubert     case UPDATE_FULL_RESYNC_NEEDED:
79*7f2fe78bSCy Schubert 	printf("%s: end (FR NEEDED)\n", w);
80*7f2fe78bSCy Schubert 	break;
81*7f2fe78bSCy Schubert     case UPDATE_BUSY:
82*7f2fe78bSCy Schubert 	printf("%s: end (BUSY)\n", w);
83*7f2fe78bSCy Schubert 	break;
84*7f2fe78bSCy Schubert     case UPDATE_NIL:
85*7f2fe78bSCy Schubert 	printf("%s: end (NIL)\n", w);
86*7f2fe78bSCy Schubert 	break;
87*7f2fe78bSCy Schubert     case UPDATE_PERM_DENIED:
88*7f2fe78bSCy Schubert 	printf("%s: end (PERM)\n", w);
89*7f2fe78bSCy Schubert 	break;
90*7f2fe78bSCy Schubert     default:
91*7f2fe78bSCy Schubert 	printf("%s: end (UNKNOWN return code (%d))\n", w, ret);
92*7f2fe78bSCy Schubert     }
93*7f2fe78bSCy Schubert }
94*7f2fe78bSCy Schubert 
95*7f2fe78bSCy Schubert static char *
replystr(update_status_t ret)96*7f2fe78bSCy Schubert replystr(update_status_t ret)
97*7f2fe78bSCy Schubert {
98*7f2fe78bSCy Schubert     switch (ret) {
99*7f2fe78bSCy Schubert     case UPDATE_OK:
100*7f2fe78bSCy Schubert 	return (reply_ok_str);
101*7f2fe78bSCy Schubert     case UPDATE_ERROR:
102*7f2fe78bSCy Schubert 	return (reply_err_str);
103*7f2fe78bSCy Schubert     case UPDATE_FULL_RESYNC_NEEDED:
104*7f2fe78bSCy Schubert 	return (reply_fr_str);
105*7f2fe78bSCy Schubert     case UPDATE_BUSY:
106*7f2fe78bSCy Schubert 	return (reply_busy_str);
107*7f2fe78bSCy Schubert     case UPDATE_NIL:
108*7f2fe78bSCy Schubert 	return (reply_nil_str);
109*7f2fe78bSCy Schubert     case UPDATE_PERM_DENIED:
110*7f2fe78bSCy Schubert 	return (reply_perm_str);
111*7f2fe78bSCy Schubert     default:
112*7f2fe78bSCy Schubert 	return (reply_unknown_str);
113*7f2fe78bSCy Schubert     }
114*7f2fe78bSCy Schubert }
115*7f2fe78bSCy Schubert 
116*7f2fe78bSCy Schubert /* Returns null on allocation failure.
117*7f2fe78bSCy Schubert    Regardless of success or failure, frees the input buffer.  */
118*7f2fe78bSCy Schubert static char *
buf_to_string(gss_buffer_desc * b)119*7f2fe78bSCy Schubert buf_to_string(gss_buffer_desc *b)
120*7f2fe78bSCy Schubert {
121*7f2fe78bSCy Schubert     OM_uint32 min_stat;
122*7f2fe78bSCy Schubert     char *s = malloc(b->length+1);
123*7f2fe78bSCy Schubert 
124*7f2fe78bSCy Schubert     if (s) {
125*7f2fe78bSCy Schubert 	memcpy(s, b->value, b->length);
126*7f2fe78bSCy Schubert 	s[b->length] = 0;
127*7f2fe78bSCy Schubert     }
128*7f2fe78bSCy Schubert     (void) gss_release_buffer(&min_stat, b);
129*7f2fe78bSCy Schubert     return s;
130*7f2fe78bSCy Schubert }
131*7f2fe78bSCy Schubert 
132*7f2fe78bSCy Schubert static krb5_boolean
iprop_acl_check(krb5_context context,const char * client_name)133*7f2fe78bSCy Schubert iprop_acl_check(krb5_context context, const char *client_name)
134*7f2fe78bSCy Schubert {
135*7f2fe78bSCy Schubert     krb5_principal client_princ;
136*7f2fe78bSCy Schubert     krb5_boolean result;
137*7f2fe78bSCy Schubert 
138*7f2fe78bSCy Schubert     if (krb5_parse_name(context, client_name, &client_princ) != 0)
139*7f2fe78bSCy Schubert 	return FALSE;
140*7f2fe78bSCy Schubert     result = auth(context, OP_IPROP, client_princ,
141*7f2fe78bSCy Schubert 		  NULL, NULL, NULL, NULL, NULL, 0);
142*7f2fe78bSCy Schubert     krb5_free_principal(context, client_princ);
143*7f2fe78bSCy Schubert     return result;
144*7f2fe78bSCy Schubert }
145*7f2fe78bSCy Schubert 
146*7f2fe78bSCy Schubert kdb_incr_result_t *
iprop_get_updates_1_svc(kdb_last_t * arg,struct svc_req * rqstp)147*7f2fe78bSCy Schubert iprop_get_updates_1_svc(kdb_last_t *arg, struct svc_req *rqstp)
148*7f2fe78bSCy Schubert {
149*7f2fe78bSCy Schubert     static kdb_incr_result_t ret;
150*7f2fe78bSCy Schubert     char *whoami = "iprop_get_updates_1";
151*7f2fe78bSCy Schubert     int kret;
152*7f2fe78bSCy Schubert     kadm5_server_handle_t handle = global_server_handle;
153*7f2fe78bSCy Schubert     char *client_name = 0, *service_name = 0;
154*7f2fe78bSCy Schubert     char obuf[256] = {0};
155*7f2fe78bSCy Schubert 
156*7f2fe78bSCy Schubert     /* default return code */
157*7f2fe78bSCy Schubert     ret.ret = UPDATE_ERROR;
158*7f2fe78bSCy Schubert 
159*7f2fe78bSCy Schubert     DPRINT("%s: start, last_sno=%lu\n", whoami,
160*7f2fe78bSCy Schubert 	    (unsigned long)arg->last_sno);
161*7f2fe78bSCy Schubert 
162*7f2fe78bSCy Schubert     if (!handle) {
163*7f2fe78bSCy Schubert 	krb5_klog_syslog(LOG_ERR,
164*7f2fe78bSCy Schubert 			 _("%s: server handle is NULL"),
165*7f2fe78bSCy Schubert 			 whoami);
166*7f2fe78bSCy Schubert 	goto out;
167*7f2fe78bSCy Schubert     }
168*7f2fe78bSCy Schubert 
169*7f2fe78bSCy Schubert     {
170*7f2fe78bSCy Schubert 	gss_buffer_desc client_desc, service_desc;
171*7f2fe78bSCy Schubert 
172*7f2fe78bSCy Schubert 	if (setup_gss_names(rqstp, &client_desc, &service_desc) < 0) {
173*7f2fe78bSCy Schubert 	    krb5_klog_syslog(LOG_ERR,
174*7f2fe78bSCy Schubert 			     _("%s: setup_gss_names failed"),
175*7f2fe78bSCy Schubert 			     whoami);
176*7f2fe78bSCy Schubert 	    goto out;
177*7f2fe78bSCy Schubert 	}
178*7f2fe78bSCy Schubert 	client_name = buf_to_string(&client_desc);
179*7f2fe78bSCy Schubert 	service_name = buf_to_string(&service_desc);
180*7f2fe78bSCy Schubert 	if (client_name == NULL || service_name == NULL) {
181*7f2fe78bSCy Schubert 	    krb5_klog_syslog(LOG_ERR,
182*7f2fe78bSCy Schubert 			     _("%s: out of memory recording principal names"),
183*7f2fe78bSCy Schubert 			     whoami);
184*7f2fe78bSCy Schubert 	    goto out;
185*7f2fe78bSCy Schubert 	}
186*7f2fe78bSCy Schubert     }
187*7f2fe78bSCy Schubert 
188*7f2fe78bSCy Schubert     DPRINT("%s: clprinc=`%s'\n\tsvcprinc=`%s'\n", whoami, client_name,
189*7f2fe78bSCy Schubert 	   service_name);
190*7f2fe78bSCy Schubert 
191*7f2fe78bSCy Schubert     if (!iprop_acl_check(handle->context, client_name)) {
192*7f2fe78bSCy Schubert 	ret.ret = UPDATE_PERM_DENIED;
193*7f2fe78bSCy Schubert 
194*7f2fe78bSCy Schubert 	DPRINT("%s: PERMISSION DENIED: clprinc=`%s'\n\tsvcprinc=`%s'\n",
195*7f2fe78bSCy Schubert 		whoami, client_name, service_name);
196*7f2fe78bSCy Schubert 
197*7f2fe78bSCy Schubert 	krb5_klog_syslog(LOG_NOTICE, LOG_UNAUTH, whoami,
198*7f2fe78bSCy Schubert 			 client_name, service_name,
199*7f2fe78bSCy Schubert 			 client_addr(rqstp->rq_xprt));
200*7f2fe78bSCy Schubert 	goto out;
201*7f2fe78bSCy Schubert     }
202*7f2fe78bSCy Schubert 
203*7f2fe78bSCy Schubert     kret = ulog_get_entries(handle->context, arg, &ret);
204*7f2fe78bSCy Schubert 
205*7f2fe78bSCy Schubert     if (ret.ret == UPDATE_OK) {
206*7f2fe78bSCy Schubert 	(void) snprintf(obuf, sizeof (obuf),
207*7f2fe78bSCy Schubert 			_("%s; Incoming SerialNo=%lu; Outgoing SerialNo=%lu"),
208*7f2fe78bSCy Schubert 			replystr(ret.ret),
209*7f2fe78bSCy Schubert 			(unsigned long)arg->last_sno,
210*7f2fe78bSCy Schubert 			(unsigned long)ret.lastentry.last_sno);
211*7f2fe78bSCy Schubert     } else {
212*7f2fe78bSCy Schubert 	(void) snprintf(obuf, sizeof (obuf),
213*7f2fe78bSCy Schubert 			_("%s; Incoming SerialNo=%lu; Outgoing SerialNo=N/A"),
214*7f2fe78bSCy Schubert 			replystr(ret.ret),
215*7f2fe78bSCy Schubert 			(unsigned long)arg->last_sno);
216*7f2fe78bSCy Schubert     }
217*7f2fe78bSCy Schubert 
218*7f2fe78bSCy Schubert     DPRINT("%s: request %s %s\n\tclprinc=`%s'\n\tsvcprinc=`%s'\n",
219*7f2fe78bSCy Schubert 	   whoami, obuf,
220*7f2fe78bSCy Schubert 	   ((kret == 0) ? "success" : error_message(kret)),
221*7f2fe78bSCy Schubert 	   client_name, service_name);
222*7f2fe78bSCy Schubert 
223*7f2fe78bSCy Schubert     krb5_klog_syslog(LOG_NOTICE,
224*7f2fe78bSCy Schubert 		     _("Request: %s, %s, %s, client=%s, service=%s, addr=%s"),
225*7f2fe78bSCy Schubert 		     whoami,
226*7f2fe78bSCy Schubert 		     obuf,
227*7f2fe78bSCy Schubert 		     ((kret == 0) ? "success" : error_message(kret)),
228*7f2fe78bSCy Schubert 		     client_name, service_name,
229*7f2fe78bSCy Schubert 		     client_addr(rqstp->rq_xprt));
230*7f2fe78bSCy Schubert 
231*7f2fe78bSCy Schubert out:
232*7f2fe78bSCy Schubert     if (nofork)
233*7f2fe78bSCy Schubert 	debprret(whoami, ret.ret, ret.lastentry.last_sno);
234*7f2fe78bSCy Schubert     free(client_name);
235*7f2fe78bSCy Schubert     free(service_name);
236*7f2fe78bSCy Schubert     return (&ret);
237*7f2fe78bSCy Schubert }
238*7f2fe78bSCy Schubert 
239*7f2fe78bSCy Schubert 
240*7f2fe78bSCy Schubert /*
241*7f2fe78bSCy Schubert  * Given a client princ (foo/fqdn@R), copy (in arg cl) the fqdn substring.
242*7f2fe78bSCy Schubert  * Return arg cl str ptr on success, else NULL.
243*7f2fe78bSCy Schubert  */
244*7f2fe78bSCy Schubert static char *
getclhoststr(const char * clprinc,char * cl,size_t len)245*7f2fe78bSCy Schubert getclhoststr(const char *clprinc, char *cl, size_t len)
246*7f2fe78bSCy Schubert {
247*7f2fe78bSCy Schubert     const char *s, *e;
248*7f2fe78bSCy Schubert 
249*7f2fe78bSCy Schubert     if ((s = strchr(clprinc, '/')) == NULL || (e = strchr(++s, '@')) == NULL ||
250*7f2fe78bSCy Schubert 	(size_t)(e - s) >= len)
251*7f2fe78bSCy Schubert 	return NULL;
252*7f2fe78bSCy Schubert     memcpy(cl, s, e - s);
253*7f2fe78bSCy Schubert     cl[e - s] = '\0';
254*7f2fe78bSCy Schubert     return (cl);
255*7f2fe78bSCy Schubert }
256*7f2fe78bSCy Schubert 
257*7f2fe78bSCy Schubert static kdb_fullresync_result_t *
ipropx_resync(uint32_t vers,struct svc_req * rqstp)258*7f2fe78bSCy Schubert ipropx_resync(uint32_t vers, struct svc_req *rqstp)
259*7f2fe78bSCy Schubert {
260*7f2fe78bSCy Schubert     static kdb_fullresync_result_t ret;
261*7f2fe78bSCy Schubert     char *ubuf = 0;
262*7f2fe78bSCy Schubert     char clhost[NI_MAXHOST] = {0};
263*7f2fe78bSCy Schubert     int pret, fret;
264*7f2fe78bSCy Schubert     FILE *p;
265*7f2fe78bSCy Schubert     kadm5_server_handle_t handle = global_server_handle;
266*7f2fe78bSCy Schubert     char *client_name = NULL, *service_name = NULL;
267*7f2fe78bSCy Schubert     char *whoami = "iprop_full_resync_1";
268*7f2fe78bSCy Schubert 
269*7f2fe78bSCy Schubert     /*
270*7f2fe78bSCy Schubert      * vers contains the highest version number the client is
271*7f2fe78bSCy Schubert      * willing to accept. A client can always accept a lower
272*7f2fe78bSCy Schubert      * version: the version number is indicated in the dump
273*7f2fe78bSCy Schubert      * header.
274*7f2fe78bSCy Schubert      */
275*7f2fe78bSCy Schubert 
276*7f2fe78bSCy Schubert     /* default return code */
277*7f2fe78bSCy Schubert     ret.ret = UPDATE_ERROR;
278*7f2fe78bSCy Schubert 
279*7f2fe78bSCy Schubert     if (!handle) {
280*7f2fe78bSCy Schubert 	krb5_klog_syslog(LOG_ERR,
281*7f2fe78bSCy Schubert 			 _("%s: server handle is NULL"),
282*7f2fe78bSCy Schubert 			 whoami);
283*7f2fe78bSCy Schubert 	goto out;
284*7f2fe78bSCy Schubert     }
285*7f2fe78bSCy Schubert 
286*7f2fe78bSCy Schubert     DPRINT("%s: start\n", whoami);
287*7f2fe78bSCy Schubert 
288*7f2fe78bSCy Schubert     {
289*7f2fe78bSCy Schubert 	gss_buffer_desc client_desc, service_desc;
290*7f2fe78bSCy Schubert 
291*7f2fe78bSCy Schubert 	if (setup_gss_names(rqstp, &client_desc, &service_desc) < 0) {
292*7f2fe78bSCy Schubert 	    DPRINT("%s: setup_gss_names failed\n", whoami);
293*7f2fe78bSCy Schubert 	    krb5_klog_syslog(LOG_ERR,
294*7f2fe78bSCy Schubert 			     _("%s: setup_gss_names failed"),
295*7f2fe78bSCy Schubert 			     whoami);
296*7f2fe78bSCy Schubert 	    goto out;
297*7f2fe78bSCy Schubert 	}
298*7f2fe78bSCy Schubert 	client_name = buf_to_string(&client_desc);
299*7f2fe78bSCy Schubert 	service_name = buf_to_string(&service_desc);
300*7f2fe78bSCy Schubert 	if (client_name == NULL || service_name == NULL) {
301*7f2fe78bSCy Schubert 	    DPRINT("%s: out of memory\n", whoami);
302*7f2fe78bSCy Schubert 	    krb5_klog_syslog(LOG_ERR,
303*7f2fe78bSCy Schubert 			     _("%s: out of memory recording principal names"),
304*7f2fe78bSCy Schubert 			     whoami);
305*7f2fe78bSCy Schubert 	    goto out;
306*7f2fe78bSCy Schubert 	}
307*7f2fe78bSCy Schubert     }
308*7f2fe78bSCy Schubert 
309*7f2fe78bSCy Schubert     DPRINT("%s: clprinc=`%s'\n\tsvcprinc=`%s'\n",
310*7f2fe78bSCy Schubert 	    whoami, client_name, service_name);
311*7f2fe78bSCy Schubert 
312*7f2fe78bSCy Schubert     if (!iprop_acl_check(handle->context, client_name)) {
313*7f2fe78bSCy Schubert 	ret.ret = UPDATE_PERM_DENIED;
314*7f2fe78bSCy Schubert 
315*7f2fe78bSCy Schubert 	DPRINT("%s: Permission denied\n", whoami);
316*7f2fe78bSCy Schubert 	krb5_klog_syslog(LOG_NOTICE, LOG_UNAUTH, whoami,
317*7f2fe78bSCy Schubert 			 client_name, service_name,
318*7f2fe78bSCy Schubert 			 client_addr(rqstp->rq_xprt));
319*7f2fe78bSCy Schubert 	goto out;
320*7f2fe78bSCy Schubert     }
321*7f2fe78bSCy Schubert 
322*7f2fe78bSCy Schubert     if (!getclhoststr(client_name, clhost, sizeof (clhost))) {
323*7f2fe78bSCy Schubert 	krb5_klog_syslog(LOG_ERR,
324*7f2fe78bSCy Schubert 			 _("%s: getclhoststr failed"),
325*7f2fe78bSCy Schubert 			 whoami);
326*7f2fe78bSCy Schubert 	goto out;
327*7f2fe78bSCy Schubert     }
328*7f2fe78bSCy Schubert 
329*7f2fe78bSCy Schubert     /*
330*7f2fe78bSCy Schubert      * Note the -i; modified version of kdb5_util dump format
331*7f2fe78bSCy Schubert      * to include sno (serial number). This argument is now
332*7f2fe78bSCy Schubert      * versioned (-i0 for legacy dump format, -i1 for ipropx
333*7f2fe78bSCy Schubert      * version 1 format, etc).
334*7f2fe78bSCy Schubert      *
335*7f2fe78bSCy Schubert      * The -c option ("conditional") causes the dump to dump only if no
336*7f2fe78bSCy Schubert      * dump already exists or that dump is not in ipropx format, or the
337*7f2fe78bSCy Schubert      * sno and timestamp in the header of that dump are outside the
338*7f2fe78bSCy Schubert      * ulog.  This allows us to share a single global dump with all
339*7f2fe78bSCy Schubert      * replicas, since it's OK to share an older dump, as long as its
340*7f2fe78bSCy Schubert      * sno and timestamp are in the ulog (then the replicas can get the
341*7f2fe78bSCy Schubert      * subsequent updates very iprop).
342*7f2fe78bSCy Schubert      */
343*7f2fe78bSCy Schubert     if (asprintf(&ubuf, "%s -r %s dump -i%d -c %s", kdb5_util,
344*7f2fe78bSCy Schubert 		 handle->params.realm, vers, dump_file) < 0) {
345*7f2fe78bSCy Schubert 	krb5_klog_syslog(LOG_ERR,
346*7f2fe78bSCy Schubert 			 _("%s: cannot construct kdb5 util dump string too long; out of memory"),
347*7f2fe78bSCy Schubert 			 whoami);
348*7f2fe78bSCy Schubert 	goto out;
349*7f2fe78bSCy Schubert     }
350*7f2fe78bSCy Schubert 
351*7f2fe78bSCy Schubert     /*
352*7f2fe78bSCy Schubert      * Fork to dump the db and xfer it to the replica.
353*7f2fe78bSCy Schubert      * (the fork allows parent to return quickly and the child
354*7f2fe78bSCy Schubert      * acts like a callback to the replica).
355*7f2fe78bSCy Schubert      */
356*7f2fe78bSCy Schubert     fret = fork();
357*7f2fe78bSCy Schubert     DPRINT("%s: fork=%d (%d)\n", whoami, fret, getpid());
358*7f2fe78bSCy Schubert 
359*7f2fe78bSCy Schubert     switch (fret) {
360*7f2fe78bSCy Schubert     case -1: /* error */
361*7f2fe78bSCy Schubert 	if (nofork) {
362*7f2fe78bSCy Schubert 	    perror(whoami);
363*7f2fe78bSCy Schubert 	}
364*7f2fe78bSCy Schubert 	DPRINT("%s: fork failed\n", whoami);
365*7f2fe78bSCy Schubert 	krb5_klog_syslog(LOG_ERR,
366*7f2fe78bSCy Schubert 			 _("%s: fork failed: %s"),
367*7f2fe78bSCy Schubert 			 whoami,
368*7f2fe78bSCy Schubert 			 error_message(errno));
369*7f2fe78bSCy Schubert 	goto out;
370*7f2fe78bSCy Schubert 
371*7f2fe78bSCy Schubert     case 0: /* child */
372*7f2fe78bSCy Schubert 	DPRINT("%s: run `%s' ...\n", whoami, ubuf);
373*7f2fe78bSCy Schubert 	(void) signal(SIGCHLD, SIG_DFL);
374*7f2fe78bSCy Schubert 	/* run kdb5_util(1M) dump for IProp */
375*7f2fe78bSCy Schubert 	p = popen(ubuf, "w");
376*7f2fe78bSCy Schubert 	if (p == NULL) {
377*7f2fe78bSCy Schubert 	    krb5_klog_syslog(LOG_ERR,
378*7f2fe78bSCy Schubert 			     _("%s: popen failed: %s"),
379*7f2fe78bSCy Schubert 			     whoami, error_message(errno));
380*7f2fe78bSCy Schubert 	    _exit(1);
381*7f2fe78bSCy Schubert 	}
382*7f2fe78bSCy Schubert 	pret = pclose(p);
383*7f2fe78bSCy Schubert 	DPRINT("%s: pclose=%d\n", whoami, pret);
384*7f2fe78bSCy Schubert 	if (pret != 0) {
385*7f2fe78bSCy Schubert 	    /* XXX popen/pclose may not set errno
386*7f2fe78bSCy Schubert 	       properly, and the error could be from the
387*7f2fe78bSCy Schubert 	       subprocess anyways.  */
388*7f2fe78bSCy Schubert 	    if (nofork) {
389*7f2fe78bSCy Schubert 		perror(whoami);
390*7f2fe78bSCy Schubert 	    }
391*7f2fe78bSCy Schubert 	    krb5_klog_syslog(LOG_ERR,
392*7f2fe78bSCy Schubert 			     _("%s: pclose(popen) failed: %s"),
393*7f2fe78bSCy Schubert 			     whoami,
394*7f2fe78bSCy Schubert 			     error_message(errno));
395*7f2fe78bSCy Schubert 	    _exit(1);
396*7f2fe78bSCy Schubert 	}
397*7f2fe78bSCy Schubert 
398*7f2fe78bSCy Schubert 	if (kprop_port != NULL) {
399*7f2fe78bSCy Schubert 	    DPRINT("%s: exec `kprop -r %s -f %s -P %s %s' ...\n",
400*7f2fe78bSCy Schubert 		   whoami, handle->params.realm, dump_file, kprop_port,
401*7f2fe78bSCy Schubert 		   clhost);
402*7f2fe78bSCy Schubert 	    pret = execl(kprop, "kprop", "-r", handle->params.realm, "-f",
403*7f2fe78bSCy Schubert 			 dump_file, "-P", kprop_port, clhost, NULL);
404*7f2fe78bSCy Schubert 	} else {
405*7f2fe78bSCy Schubert 	    DPRINT("%s: exec `kprop -r %s -f %s %s' ...\n",
406*7f2fe78bSCy Schubert 		   whoami, handle->params.realm, dump_file, clhost);
407*7f2fe78bSCy Schubert 	    pret = execl(kprop, "kprop", "-r", handle->params.realm, "-f",
408*7f2fe78bSCy Schubert 			 dump_file, clhost, NULL);
409*7f2fe78bSCy Schubert 	}
410*7f2fe78bSCy Schubert 	perror(whoami);
411*7f2fe78bSCy Schubert 	krb5_klog_syslog(LOG_ERR,
412*7f2fe78bSCy Schubert 			 _("%s: exec failed: %s"),
413*7f2fe78bSCy Schubert 			 whoami,
414*7f2fe78bSCy Schubert 			 error_message(errno));
415*7f2fe78bSCy Schubert 	_exit(1);
416*7f2fe78bSCy Schubert 
417*7f2fe78bSCy Schubert     default: /* parent */
418*7f2fe78bSCy Schubert 	ret.ret = UPDATE_OK;
419*7f2fe78bSCy Schubert 	/* not used by replica (sno is retrieved from kdb5_util dump) */
420*7f2fe78bSCy Schubert 	ret.lastentry.last_sno = 0;
421*7f2fe78bSCy Schubert 	ret.lastentry.last_time.seconds = 0;
422*7f2fe78bSCy Schubert 	ret.lastentry.last_time.useconds = 0;
423*7f2fe78bSCy Schubert 
424*7f2fe78bSCy Schubert 	DPRINT("%s: spawned resync process %d, client=%s, "
425*7f2fe78bSCy Schubert 		"service=%s, addr=%s\n", whoami, fret, client_name,
426*7f2fe78bSCy Schubert 		service_name, client_addr(rqstp->rq_xprt));
427*7f2fe78bSCy Schubert 	krb5_klog_syslog(LOG_NOTICE,
428*7f2fe78bSCy Schubert 			 _("Request: %s, spawned resync process %d, client=%s, service=%s, addr=%s"),
429*7f2fe78bSCy Schubert 			 whoami, fret,
430*7f2fe78bSCy Schubert 			 client_name, service_name,
431*7f2fe78bSCy Schubert 			 client_addr(rqstp->rq_xprt));
432*7f2fe78bSCy Schubert 
433*7f2fe78bSCy Schubert 	goto out;
434*7f2fe78bSCy Schubert     }
435*7f2fe78bSCy Schubert 
436*7f2fe78bSCy Schubert out:
437*7f2fe78bSCy Schubert     if (nofork)
438*7f2fe78bSCy Schubert 	debprret(whoami, ret.ret, 0);
439*7f2fe78bSCy Schubert     free(client_name);
440*7f2fe78bSCy Schubert     free(service_name);
441*7f2fe78bSCy Schubert     free(ubuf);
442*7f2fe78bSCy Schubert     return (&ret);
443*7f2fe78bSCy Schubert }
444*7f2fe78bSCy Schubert 
445*7f2fe78bSCy Schubert kdb_fullresync_result_t *
iprop_full_resync_1_svc(void * argp,struct svc_req * rqstp)446*7f2fe78bSCy Schubert iprop_full_resync_1_svc(/* LINTED */ void *argp, struct svc_req *rqstp)
447*7f2fe78bSCy Schubert {
448*7f2fe78bSCy Schubert     return ipropx_resync(IPROPX_VERSION_0, rqstp);
449*7f2fe78bSCy Schubert }
450*7f2fe78bSCy Schubert 
451*7f2fe78bSCy Schubert kdb_fullresync_result_t *
iprop_full_resync_ext_1_svc(uint32_t * argp,struct svc_req * rqstp)452*7f2fe78bSCy Schubert iprop_full_resync_ext_1_svc(uint32_t *argp, struct svc_req *rqstp)
453*7f2fe78bSCy Schubert {
454*7f2fe78bSCy Schubert     return ipropx_resync(*argp, rqstp);
455*7f2fe78bSCy Schubert }
456*7f2fe78bSCy Schubert 
457*7f2fe78bSCy Schubert static int
check_iprop_rpcsec_auth(struct svc_req * rqstp)458*7f2fe78bSCy Schubert check_iprop_rpcsec_auth(struct svc_req *rqstp)
459*7f2fe78bSCy Schubert {
460*7f2fe78bSCy Schubert     /* XXX Since the client can authenticate against any principal in
461*7f2fe78bSCy Schubert        the database, we need to do a sanity check.  Only checking for
462*7f2fe78bSCy Schubert        "kiprop" now, but that means theoretically the client could be
463*7f2fe78bSCy Schubert        authenticating to kiprop on some other machine.  */
464*7f2fe78bSCy Schubert     /* Code taken from kadm_rpc_svc.c, tweaked.  */
465*7f2fe78bSCy Schubert 
466*7f2fe78bSCy Schubert      gss_ctx_id_t ctx;
467*7f2fe78bSCy Schubert      krb5_context kctx;
468*7f2fe78bSCy Schubert      OM_uint32 maj_stat, min_stat;
469*7f2fe78bSCy Schubert      gss_name_t name;
470*7f2fe78bSCy Schubert      krb5_principal princ;
471*7f2fe78bSCy Schubert      int ret, success;
472*7f2fe78bSCy Schubert      krb5_data *c1, *realm;
473*7f2fe78bSCy Schubert      gss_buffer_desc gss_str;
474*7f2fe78bSCy Schubert      kadm5_server_handle_t handle;
475*7f2fe78bSCy Schubert      size_t slen;
476*7f2fe78bSCy Schubert      char *sdots;
477*7f2fe78bSCy Schubert 
478*7f2fe78bSCy Schubert      success = 0;
479*7f2fe78bSCy Schubert      handle = (kadm5_server_handle_t)global_server_handle;
480*7f2fe78bSCy Schubert 
481*7f2fe78bSCy Schubert      if (rqstp->rq_cred.oa_flavor != RPCSEC_GSS)
482*7f2fe78bSCy Schubert 	  return 0;
483*7f2fe78bSCy Schubert 
484*7f2fe78bSCy Schubert      ctx = rqstp->rq_svccred;
485*7f2fe78bSCy Schubert 
486*7f2fe78bSCy Schubert      maj_stat = gss_inquire_context(&min_stat, ctx, NULL, &name,
487*7f2fe78bSCy Schubert 				    NULL, NULL, NULL, NULL, NULL);
488*7f2fe78bSCy Schubert      if (maj_stat != GSS_S_COMPLETE) {
489*7f2fe78bSCy Schubert 	  krb5_klog_syslog(LOG_ERR,
490*7f2fe78bSCy Schubert 			   _("check_rpcsec_auth: failed inquire_context, "
491*7f2fe78bSCy Schubert 			     "stat=%u"), maj_stat);
492*7f2fe78bSCy Schubert 	  log_badauth(maj_stat, min_stat, rqstp->rq_xprt, NULL);
493*7f2fe78bSCy Schubert 	  goto fail_name;
494*7f2fe78bSCy Schubert      }
495*7f2fe78bSCy Schubert 
496*7f2fe78bSCy Schubert      kctx = handle->context;
497*7f2fe78bSCy Schubert      ret = gss_to_krb5_name_1(rqstp, kctx, name, &princ, &gss_str);
498*7f2fe78bSCy Schubert      if (ret == 0)
499*7f2fe78bSCy Schubert 	  goto fail_name;
500*7f2fe78bSCy Schubert 
501*7f2fe78bSCy Schubert      slen = gss_str.length;
502*7f2fe78bSCy Schubert      trunc_name(&slen, &sdots);
503*7f2fe78bSCy Schubert      /*
504*7f2fe78bSCy Schubert       * Since we accept with GSS_C_NO_NAME, the client can authenticate
505*7f2fe78bSCy Schubert       * against the entire kdb.  Therefore, ensure that the service
506*7f2fe78bSCy Schubert       * name is something reasonable.
507*7f2fe78bSCy Schubert       */
508*7f2fe78bSCy Schubert      if (krb5_princ_size(kctx, princ) != 2)
509*7f2fe78bSCy Schubert 	  goto fail_princ;
510*7f2fe78bSCy Schubert 
511*7f2fe78bSCy Schubert      c1 = krb5_princ_component(kctx, princ, 0);
512*7f2fe78bSCy Schubert      realm = krb5_princ_realm(kctx, princ);
513*7f2fe78bSCy Schubert      if (strncmp(handle->params.realm, realm->data, realm->length) == 0
514*7f2fe78bSCy Schubert 	 && strncmp("kiprop", c1->data, c1->length) == 0) {
515*7f2fe78bSCy Schubert 	 success = 1;
516*7f2fe78bSCy Schubert      }
517*7f2fe78bSCy Schubert 
518*7f2fe78bSCy Schubert fail_princ:
519*7f2fe78bSCy Schubert      if (!success) {
520*7f2fe78bSCy Schubert 	  krb5_klog_syslog(LOG_ERR, _("bad service principal %.*s%s"),
521*7f2fe78bSCy Schubert 			   (int) slen, (char *) gss_str.value, sdots);
522*7f2fe78bSCy Schubert      }
523*7f2fe78bSCy Schubert      gss_release_buffer(&min_stat, &gss_str);
524*7f2fe78bSCy Schubert      krb5_free_principal(kctx, princ);
525*7f2fe78bSCy Schubert fail_name:
526*7f2fe78bSCy Schubert      gss_release_name(&min_stat, &name);
527*7f2fe78bSCy Schubert      return success;
528*7f2fe78bSCy Schubert }
529*7f2fe78bSCy Schubert 
530*7f2fe78bSCy Schubert void
krb5_iprop_prog_1(struct svc_req * rqstp,SVCXPRT * transp)531*7f2fe78bSCy Schubert krb5_iprop_prog_1(struct svc_req *rqstp,
532*7f2fe78bSCy Schubert 		  SVCXPRT *transp)
533*7f2fe78bSCy Schubert {
534*7f2fe78bSCy Schubert     union {
535*7f2fe78bSCy Schubert 	kdb_last_t iprop_get_updates_1_arg;
536*7f2fe78bSCy Schubert     } argument;
537*7f2fe78bSCy Schubert     void *result;
538*7f2fe78bSCy Schubert     bool_t (*_xdr_argument)(), (*_xdr_result)();
539*7f2fe78bSCy Schubert     void *(*local)(/* union XXX *, struct svc_req * */);
540*7f2fe78bSCy Schubert     char *whoami = "krb5_iprop_prog_1";
541*7f2fe78bSCy Schubert 
542*7f2fe78bSCy Schubert     if (!check_iprop_rpcsec_auth(rqstp)) {
543*7f2fe78bSCy Schubert 	krb5_klog_syslog(LOG_ERR, _("authentication attempt failed: %s, RPC "
544*7f2fe78bSCy Schubert 				    "authentication flavor %d"),
545*7f2fe78bSCy Schubert 			 client_addr(rqstp->rq_xprt),
546*7f2fe78bSCy Schubert 			 rqstp->rq_cred.oa_flavor);
547*7f2fe78bSCy Schubert 	svcerr_weakauth(transp);
548*7f2fe78bSCy Schubert 	return;
549*7f2fe78bSCy Schubert     }
550*7f2fe78bSCy Schubert 
551*7f2fe78bSCy Schubert     switch (rqstp->rq_proc) {
552*7f2fe78bSCy Schubert     case NULLPROC:
553*7f2fe78bSCy Schubert 	(void) svc_sendreply(transp, xdr_void,
554*7f2fe78bSCy Schubert 			     (char *)NULL);
555*7f2fe78bSCy Schubert 	return;
556*7f2fe78bSCy Schubert 
557*7f2fe78bSCy Schubert     case IPROP_GET_UPDATES:
558*7f2fe78bSCy Schubert 	_xdr_argument = xdr_kdb_last_t;
559*7f2fe78bSCy Schubert 	_xdr_result = xdr_kdb_incr_result_t;
560*7f2fe78bSCy Schubert 	local = (void *(*)()) iprop_get_updates_1_svc;
561*7f2fe78bSCy Schubert 	break;
562*7f2fe78bSCy Schubert 
563*7f2fe78bSCy Schubert     case IPROP_FULL_RESYNC:
564*7f2fe78bSCy Schubert 	_xdr_argument = xdr_void;
565*7f2fe78bSCy Schubert 	_xdr_result = xdr_kdb_fullresync_result_t;
566*7f2fe78bSCy Schubert 	local = (void *(*)()) iprop_full_resync_1_svc;
567*7f2fe78bSCy Schubert 	break;
568*7f2fe78bSCy Schubert 
569*7f2fe78bSCy Schubert     case IPROP_FULL_RESYNC_EXT:
570*7f2fe78bSCy Schubert 	_xdr_argument = xdr_u_int32;
571*7f2fe78bSCy Schubert 	_xdr_result = xdr_kdb_fullresync_result_t;
572*7f2fe78bSCy Schubert 	local = (void *(*)()) iprop_full_resync_ext_1_svc;
573*7f2fe78bSCy Schubert 	break;
574*7f2fe78bSCy Schubert 
575*7f2fe78bSCy Schubert     default:
576*7f2fe78bSCy Schubert 	krb5_klog_syslog(LOG_ERR,
577*7f2fe78bSCy Schubert 			 _("RPC unknown request: %d (%s)"),
578*7f2fe78bSCy Schubert 			 rqstp->rq_proc, whoami);
579*7f2fe78bSCy Schubert 	svcerr_noproc(transp);
580*7f2fe78bSCy Schubert 	return;
581*7f2fe78bSCy Schubert     }
582*7f2fe78bSCy Schubert     (void) memset(&argument, 0, sizeof (argument));
583*7f2fe78bSCy Schubert     if (!svc_getargs(transp, _xdr_argument, (caddr_t)&argument)) {
584*7f2fe78bSCy Schubert 	krb5_klog_syslog(LOG_ERR,
585*7f2fe78bSCy Schubert 			 _("RPC svc_getargs failed (%s)"),
586*7f2fe78bSCy Schubert 			 whoami);
587*7f2fe78bSCy Schubert 	svcerr_decode(transp);
588*7f2fe78bSCy Schubert 	return;
589*7f2fe78bSCy Schubert     }
590*7f2fe78bSCy Schubert     result = (*local)(&argument, rqstp);
591*7f2fe78bSCy Schubert 
592*7f2fe78bSCy Schubert     if (_xdr_result && result != NULL &&
593*7f2fe78bSCy Schubert 	!svc_sendreply(transp, _xdr_result, result)) {
594*7f2fe78bSCy Schubert 	krb5_klog_syslog(LOG_ERR,
595*7f2fe78bSCy Schubert 			 _("RPC svc_sendreply failed (%s)"),
596*7f2fe78bSCy Schubert 			 whoami);
597*7f2fe78bSCy Schubert 	svcerr_systemerr(transp);
598*7f2fe78bSCy Schubert     }
599*7f2fe78bSCy Schubert     if (!svc_freeargs(transp, _xdr_argument, (caddr_t)&argument)) {
600*7f2fe78bSCy Schubert 	krb5_klog_syslog(LOG_ERR,
601*7f2fe78bSCy Schubert 			 _("RPC svc_freeargs failed (%s)"),
602*7f2fe78bSCy Schubert 			 whoami);
603*7f2fe78bSCy Schubert 
604*7f2fe78bSCy Schubert 	exit(1);
605*7f2fe78bSCy Schubert     }
606*7f2fe78bSCy Schubert 
607*7f2fe78bSCy Schubert     if (rqstp->rq_proc == IPROP_GET_UPDATES) {
608*7f2fe78bSCy Schubert 	/* LINTED */
609*7f2fe78bSCy Schubert 	kdb_incr_result_t *r = (kdb_incr_result_t *)result;
610*7f2fe78bSCy Schubert 
611*7f2fe78bSCy Schubert 	if (r->ret == UPDATE_OK) {
612*7f2fe78bSCy Schubert 	    ulog_free_entries(r->updates.kdb_ulog_t_val,
613*7f2fe78bSCy Schubert 			      r->updates.kdb_ulog_t_len);
614*7f2fe78bSCy Schubert 	    r->updates.kdb_ulog_t_val = NULL;
615*7f2fe78bSCy Schubert 	    r->updates.kdb_ulog_t_len = 0;
616*7f2fe78bSCy Schubert 	}
617*7f2fe78bSCy Schubert     }
618*7f2fe78bSCy Schubert 
619*7f2fe78bSCy Schubert }
620