2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
7 #include <stdlib.h> /* getenv, exit */
12 #include <netconfig.h>
13 #include <sys/resource.h> /* rlimit */
16 #include <kadm5/admin.h>
17 #include <kadm5/kadm_rpc.h>
18 #include <kadm5/server_internal.h>
19 #include <server_acl.h>
20 #include <krb5/adm_proto.h>
22 #include <gssapi_krb5.h>
23 #include <sys/socket.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
28 #include <kdb/kdb_log.h>
31 extern int setup_gss_names(struct svc_req
*, char **, char **);
32 extern gss_name_t
get_clnt_name(struct svc_req
*);
33 extern char *client_addr(struct svc_req
*, char *);
34 extern void *global_server_handle
;
39 static char *reply_ok_str
= "UPDATE_OK";
40 static char *reply_err_str
= "UPDATE_ERROR";
41 static char *reply_fr_str
= "UPDATE_FULL_RESYNC_NEEDED";
42 static char *reply_busy_str
= "UPDATE_BUSY";
43 static char *reply_nil_str
= "UPDATE_NIL";
44 static char *reply_perm_str
= "UPDATE_PERM_DENIED";
45 static char *reply_unknown_str
= "<UNKNOWN_CODE>";
47 #define LOG_UNAUTH gettext("Unauthorized request: %s, %s, " \
48 "client=%s, service=%s, addr=%s")
49 #define LOG_DONE gettext("Request: %s, %s, %s, client=%s, " \
50 "service=%s, addr=%s")
52 #define KDB5_UTIL_DUMP_STR "/usr/sbin/kdb5_util dump -i "
57 #define DPRINT(i) if (nofork) printf i
60 static struct sigaction s_action
;
61 #endif /* POSIX_SIGNALS */
64 debprret(char *w
, update_status_t ret
, kdb_sno_t sno
)
68 printf("%s: end (OK, sno=%u)\n",
72 printf("%s: end (ERROR)\n", w
);
74 case UPDATE_FULL_RESYNC_NEEDED
:
75 printf("%s: end (FR NEEDED)\n", w
);
78 printf("%s: end (BUSY)\n", w
);
81 printf("%s: end (NIL)\n", w
);
83 case UPDATE_PERM_DENIED
:
84 printf("%s: end (PERM)\n", w
);
87 printf("%s: end (UNKNOWN return code (%d))\n", w
, ret
);
92 replystr(update_status_t ret
)
96 return (reply_ok_str
);
98 return (reply_err_str
);
99 case UPDATE_FULL_RESYNC_NEEDED
:
100 return (reply_fr_str
);
102 return (reply_busy_str
);
104 return (reply_nil_str
);
105 case UPDATE_PERM_DENIED
:
106 return (reply_perm_str
);
108 return (reply_unknown_str
);
113 iprop_get_updates_1(kdb_last_t
*arg
, struct svc_req
*rqstp
)
115 static kdb_incr_result_t ret
;
116 char *whoami
= "iprop_get_updates_1";
118 kadm5_server_handle_t handle
= global_server_handle
;
119 char *client_name
= NULL
, *service_name
= NULL
;
120 gss_name_t name
= NULL
;
122 char obuf
[256] = {0};
124 /* default return code */
125 ret
.ret
= UPDATE_ERROR
;
127 DPRINT(("%s: start, last_sno=%u\n", whoami
, (ulong_t
)arg
->last_sno
));
130 krb5_klog_syslog(LOG_ERR
,
131 gettext("%s: server handle is NULL"),
136 if (setup_gss_names(rqstp
, &client_name
, &service_name
) < 0) {
137 krb5_klog_syslog(LOG_ERR
,
138 gettext("%s: setup_gss_names failed"),
143 DPRINT(("%s: clprinc=`%s'\n\tsvcprinc=`%s'\n",
144 whoami
, client_name
, service_name
));
146 if (!(name
= get_clnt_name(rqstp
))) {
147 krb5_klog_syslog(LOG_ERR
,
148 gettext("%s: Couldn't obtain client's name"),
152 if (!kadm5int_acl_check(handle
->context
,
157 ret
.ret
= UPDATE_PERM_DENIED
;
159 audit_kadmind_unauth(rqstp
->rq_xprt
, l_port
,
161 "<null>", client_name
);
162 krb5_klog_syslog(LOG_NOTICE
, LOG_UNAUTH
, whoami
,
163 "<null>", client_name
, service_name
,
164 client_addr(rqstp
, abuf
));
168 kret
= ulog_get_entries(handle
->context
, *arg
, &ret
);
170 if (ret
.ret
== UPDATE_OK
) {
171 (void) snprintf(obuf
, sizeof (obuf
),
172 gettext("%s; Incoming SerialNo=%u; Outgoing SerialNo=%u"),
174 (ulong_t
)arg
->last_sno
,
175 (ulong_t
)ret
.lastentry
.last_sno
);
177 (void) snprintf(obuf
, sizeof (obuf
),
178 gettext("%s; Incoming SerialNo=%u; Outgoing SerialNo=N/A"),
180 (ulong_t
)arg
->last_sno
);
183 audit_kadmind_auth(rqstp
->rq_xprt
, l_port
,
185 obuf
, client_name
, kret
);
187 krb5_klog_syslog(LOG_NOTICE
, LOG_DONE
, whoami
,
189 ((kret
== 0) ? "success" : error_message(kret
)),
190 client_name
, service_name
,
191 client_addr(rqstp
, abuf
));
195 debprret(whoami
, ret
.ret
, ret
.lastentry
.last_sno
);
201 gss_release_name(&min_stat
, &name
);
207 * Given a client princ (foo/fqdn@R), copy (in arg cl) the fqdn substring.
208 * Return arg cl str ptr on success, else NULL.
211 getclhoststr(char *clprinc
, char *cl
, int len
)
214 if (s
= strchr(clprinc
, '/')) {
215 if (!++s
|| strlcpy(cl
, s
, len
) >= len
) {
218 if (s
= strchr(cl
, '@')) {
220 return (cl
); /* success */
227 kdb_fullresync_result_t
*
231 struct svc_req
*rqstp
)
233 static kdb_fullresync_result_t ret
;
234 char tmpf
[MAX_FILENAME
] = {0};
235 char ubuf
[MAX_FILENAME
+ sizeof (KDB5_UTIL_DUMP_STR
)] = {0};
236 char clhost
[MAXHOSTNAMELEN
] = {0};
238 kadm5_server_handle_t handle
= global_server_handle
;
240 gss_name_t name
= NULL
;
241 char *client_name
= NULL
, *service_name
= NULL
;
242 char *whoami
= "iprop_full_resync_1";
244 /* default return code */
245 ret
.ret
= UPDATE_ERROR
;
248 krb5_klog_syslog(LOG_ERR
,
249 gettext("%s: server handle is NULL"),
254 DPRINT(("%s: start\n", whoami
));
256 if (setup_gss_names(rqstp
, &client_name
, &service_name
) < 0) {
257 krb5_klog_syslog(LOG_ERR
,
258 gettext("%s: setup_gss_names failed"),
263 DPRINT(("%s: clprinc=`%s'\n\tsvcprinc=`%s'\n",
264 whoami
, client_name
, service_name
));
266 if (!(name
= get_clnt_name(rqstp
))) {
267 krb5_klog_syslog(LOG_ERR
,
268 gettext("%s: Couldn't obtain client's name"),
272 if (!kadm5int_acl_check(handle
->context
,
277 ret
.ret
= UPDATE_PERM_DENIED
;
279 audit_kadmind_unauth(rqstp
->rq_xprt
, l_port
,
281 "<null>", client_name
);
282 krb5_klog_syslog(LOG_NOTICE
, LOG_UNAUTH
, whoami
,
283 "<null>", client_name
, service_name
,
284 client_addr(rqstp
, abuf
));
288 if (!getclhoststr(client_name
, clhost
, sizeof (clhost
))) {
289 krb5_klog_syslog(LOG_ERR
,
290 gettext("%s: getclhoststr failed"),
296 * construct db dump file name; kprop style name + clnt fqdn
298 (void) strcpy(tmpf
, "/var/krb5/slave_datatrans_");
299 if (strlcat(tmpf
, clhost
, sizeof (tmpf
)) >= sizeof (tmpf
)) {
300 krb5_klog_syslog(LOG_ERR
,
301 gettext("%s: db dump file name too long; max length=%d"),
303 (sizeof (tmpf
) - 1));
308 * note the -i; modified version of kdb5_util dump format
309 * to include sno (serial number)
311 if (strlcpy(ubuf
, KDB5_UTIL_DUMP_STR
, sizeof (ubuf
)) >=
315 if (strlcat(ubuf
, tmpf
, sizeof (ubuf
)) >= sizeof (ubuf
)) {
316 krb5_klog_syslog(LOG_ERR
,
317 gettext("%s: kdb5 util dump string too long; max length=%d"),
319 (sizeof (ubuf
) - 1));
324 * Fork to dump the db and xfer it to the slave.
325 * (the fork allows parent to return quickly and the child
326 * acts like a callback to the slave).
329 DPRINT(("%s: fork=%d (%d)\n", whoami
, fret
, getpid()));
336 krb5_klog_syslog(LOG_ERR
,
337 gettext("%s: fork failed: %s"),
339 error_message(errno
));
343 DPRINT(("%s: run `%s' ...\n", whoami
, ubuf
));
345 (void) sigemptyset(&s_action
.sa_mask
);
346 s_action
.sa_handler
= SIG_DFL
;
347 (void) sigaction(SIGCHLD
, &s_action
, (struct sigaction
*) NULL
);
349 (void) signal(SIGCHLD
, SIG_DFL
);
350 #endif /* POSIX_SIGNALS */
351 /* run kdb5_util(1M) dump for IProp */
352 pret
= pclose(popen(ubuf
, "w"));
353 DPRINT(("%s: pclose=%d\n", whoami
, pret
));
358 krb5_klog_syslog(LOG_ERR
,
359 gettext("%s: pclose(popen) failed: %s"),
361 error_message(errno
));
365 DPRINT(("%s: exec `kprop -f %s %s' ...\n",
366 whoami
, tmpf
, clhost
));
367 pret
= execl("/usr/lib/krb5/kprop", "kprop", "-f", tmpf
,
373 krb5_klog_syslog(LOG_ERR
,
374 gettext("%s: exec failed: %s"),
376 error_message(errno
));
380 default: /* parent */
382 /* not used by slave (sno is retrieved from kdb5_util dump) */
383 ret
.lastentry
.last_sno
= 0;
384 ret
.lastentry
.last_time
.seconds
= 0;
385 ret
.lastentry
.last_time
.useconds
= 0;
387 audit_kadmind_auth(rqstp
->rq_xprt
, l_port
,
389 "<null>", client_name
, 0);
391 krb5_klog_syslog(LOG_NOTICE
, LOG_DONE
, whoami
,
394 client_name
, service_name
,
395 client_addr(rqstp
, abuf
));
402 debprret(whoami
, ret
.ret
, 0);
408 gss_release_name(&min_stat
, &name
);
414 struct svc_req
*rqstp
,
415 register SVCXPRT
*transp
)
418 kdb_last_t iprop_get_updates_1_arg
;
421 bool_t (*_xdr_argument
)(), (*_xdr_result
)();
423 char *whoami
= "krb5_iprop_prog_1";
425 switch (rqstp
->rq_proc
) {
427 (void) svc_sendreply(transp
, xdr_void
,
431 case IPROP_GET_UPDATES
:
432 _xdr_argument
= xdr_kdb_last_t
;
433 _xdr_result
= xdr_kdb_incr_result_t
;
434 local
= (char *(*)()) iprop_get_updates_1
;
437 case IPROP_FULL_RESYNC
:
438 _xdr_argument
= xdr_void
;
439 _xdr_result
= xdr_kdb_fullresync_result_t
;
440 local
= (char *(*)()) iprop_full_resync_1
;
444 krb5_klog_syslog(LOG_ERR
,
445 gettext("RPC unknown request: %d (%s)"),
446 rqstp
->rq_proc
, whoami
);
447 svcerr_noproc(transp
);
450 (void) memset((char *)&argument
, 0, sizeof (argument
));
451 if (!svc_getargs(transp
, _xdr_argument
, (caddr_t
)&argument
)) {
452 krb5_klog_syslog(LOG_ERR
,
453 gettext("RPC svc_getargs failed (%s)"),
455 svcerr_decode(transp
);
458 result
= (*local
)(&argument
, rqstp
);
460 if (_xdr_result
&& result
!= NULL
&&
461 !svc_sendreply(transp
, _xdr_result
, result
)) {
462 krb5_klog_syslog(LOG_ERR
,
463 gettext("RPC svc_sendreply failed (%s)"),
465 svcerr_systemerr(transp
);
467 if (!svc_freeargs(transp
, _xdr_argument
, (caddr_t
)&argument
)) {
468 krb5_klog_syslog(LOG_ERR
,
469 gettext("RPC svc_freeargs failed (%s)"),
475 if (rqstp
->rq_proc
== IPROP_GET_UPDATES
) {
477 kdb_incr_result_t
*r
= (kdb_incr_result_t
*)result
;
479 if (r
->ret
== UPDATE_OK
) {
480 ulog_free_entries(r
->updates
.kdb_ulog_t_val
,
481 r
->updates
.kdb_ulog_t_len
);
482 r
->updates
.kdb_ulog_t_val
= NULL
;
483 r
->updates
.kdb_ulog_t_len
= 0;
490 * Get the host base service name for the kiprop principal. Returns
491 * KADM5_OK on success. Caller must free the storage allocated for
495 kiprop_get_adm_host_srv_name(
496 krb5_context context
,
498 char **host_service_name
)
504 if (ret
= kadm5_get_master(context
, realm
, &host
))
507 name
= malloc(strlen(KIPROP_SVC_NAME
)+ strlen(host
) + 2);
512 (void) sprintf(name
, "%s@%s", KIPROP_SVC_NAME
, host
);
514 *host_service_name
= name
;