1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * Usermode daemon which assists the kernel when handling gssapi calls. 30 * It is gssd that actually implements all gssapi calls. 31 * Some calls, such as gss_sign, are implemented in the kernel on a per 32 * mechanism basis. 33 */ 34 35 #include <stdio.h> 36 #include <rpc/rpc.h> 37 #include <rpc/rpc_com.h> 38 #include <sys/syslog.h> 39 #include <sys/termios.h> 40 #include <unistd.h> 41 #include <sys/utsname.h> 42 #include <sys/systeminfo.h> 43 #include <stdlib.h> 44 #include <stropts.h> 45 #include <fcntl.h> 46 #include <strings.h> 47 #include <signal.h> 48 #include <syslog.h> 49 #include "gssd.h" 50 51 int gssd_debug = 0; /* enable debugging printfs */ 52 extern void gsscred_set_options(void); 53 54 void gssprog_1(); 55 void gssd_setup(char *); 56 static void usage(void); 57 static void daemonize_start(); 58 static void daemonize_ready(unsigned char status); 59 extern int svc_create_local_service(); 60 61 /* following declarations needed in rpcgen-generated code */ 62 int _rpcpmstart = 0; /* Started by a port monitor ? */ 63 int _rpcfdtype; /* Whether Stream or Datagram ? */ 64 int _rpcsvcdirty; /* Still serving ? */ 65 66 67 static void 68 /* LINTED */ 69 catch_hup(int sig_num) 70 { 71 sigset_t mask_set; /* used to set a signal masking set. */ 72 sigset_t old_set; /* used to store the old mask set. */ 73 74 /* re-set the signal handler again to catch_hup, for next time */ 75 (void) signal(SIGHUP, catch_hup); 76 /* mask any further signals while we're inside the handler. */ 77 (void) sigfillset(&mask_set); 78 (void) sigprocmask(SIG_SETMASK, &mask_set, &old_set); 79 80 gsscred_set_options(); 81 82 /* let admin know the sighup was caught and conf file re-read */ 83 syslog(LOG_INFO, 84 "catch_hup: read gsscred.conf opts"); 85 if (gssd_debug) 86 (void) fprintf(stderr, 87 "catch_hup: read gsscred.conf opts"); 88 89 (void) sigprocmask(SIG_SETMASK, &old_set, NULL); 90 } 91 92 93 int 94 main(argc, argv) 95 int argc; 96 char **argv; 97 { 98 register SVCXPRT *transp; 99 int maxrecsz = RPC_MAXDATASIZE; 100 extern int optind; 101 int c; 102 char mname[FMNAMESZ + 1]; 103 104 /* set locale and domain for internationalization */ 105 setlocale(LC_ALL, ""); 106 textdomain(TEXT_DOMAIN); 107 108 109 /* 110 * Take special note that "getuid()" is called here. This call is used 111 * rather than app_krb5_user_uid(), to ensure gssd(1M) is running as 112 * root. 113 */ 114 #ifdef DEBUG 115 (void) setuid(0); /* DEBUG: set ruid to root */ 116 #endif /* DEBUG */ 117 if (getuid()) { 118 (void) fprintf(stderr, 119 gettext("[%s] must be run as root\n"), argv[0]); 120 #ifdef DEBUG 121 (void) fprintf(stderr, gettext(" warning only\n")); 122 #else /* DEBUG */ 123 exit(1); 124 #endif /* DEBUG */ 125 } 126 127 gssd_setup(argv[0]); 128 129 while ((c = getopt(argc, argv, "d")) != -1) 130 switch (c) { 131 case 'd': 132 /* turn on debugging */ 133 gssd_debug = 1; 134 break; 135 default: 136 usage(); 137 } 138 139 if (optind != argc) { 140 usage(); 141 } 142 143 gsscred_set_options(); 144 (void) signal(SIGHUP, catch_hup); 145 146 /* 147 * Started by inetd if name of module just below stream 148 * head is either a sockmod or timod. 149 */ 150 if (!ioctl(0, I_LOOK, mname) && 151 ((strcmp(mname, "sockmod") == 0) || 152 (strcmp(mname, "timod") == 0))) { 153 154 char *netid; 155 struct netconfig *nconf; 156 157 openlog("gssd", LOG_PID, LOG_DAEMON); 158 159 if ((netid = getenv("NLSPROVIDER")) == NULL) { 160 netid = "ticotsord"; 161 } 162 163 if ((nconf = getnetconfigent(netid)) == NULL) { 164 syslog(LOG_ERR, gettext("cannot get transport info")); 165 exit(1); 166 } 167 168 if (strcmp(mname, "sockmod") == 0) { 169 if (ioctl(0, I_POP, 0) || ioctl(0, I_PUSH, "timod")) { 170 syslog(LOG_ERR, 171 gettext("could not get the " 172 "right module")); 173 exit(1); 174 } 175 } 176 if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrecsz)) { 177 syslog(LOG_ERR, 178 gettext("unable to set RPC max record size")); 179 exit(1); 180 } 181 /* XXX - is nconf even needed here? */ 182 if ((transp = svc_tli_create(0, nconf, NULL, 0, 0)) == NULL) { 183 syslog(LOG_ERR, gettext("cannot create server handle")); 184 exit(1); 185 } 186 187 /* 188 * We use a NULL nconf because GSSPROG has already been 189 * registered with rpcbind. 190 */ 191 if (!svc_reg(transp, GSSPROG, GSSVERS, gssprog_1, NULL)) { 192 syslog(LOG_ERR, 193 gettext("unable to register " 194 "(GSSPROG, GSSVERS)")); 195 exit(1); 196 } 197 198 if (nconf) 199 freenetconfigent(nconf); 200 } else { 201 if (!gssd_debug) 202 daemonize_start(); 203 204 openlog("gssd", LOG_PID, LOG_DAEMON); 205 206 if (svc_create_local_service(gssprog_1, GSSPROG, GSSVERS, 207 "netpath", "gssd") == 0) { 208 syslog(LOG_ERR, gettext("unable to create service")); 209 exit(1); 210 } 211 212 /* service created, now the daemon parent can exit */ 213 daemonize_ready(0); 214 } 215 216 217 if (gssd_debug) { 218 fprintf(stderr, 219 gettext("gssd start: \n")); 220 } 221 svc_run(); 222 abort(); 223 /*NOTREACHED*/ 224 #ifdef lint 225 return (1); 226 #endif 227 } 228 229 static void 230 usage(void) 231 { 232 (void) fprintf(stderr, gettext("usage: gssd [-dg]\n")); 233 exit(1); 234 } 235 236 237 /* 238 * Fork, detach from tty, etc... 239 */ 240 static int write_pipe_fd = -1; 241 static 242 void 243 daemonize_start() 244 { 245 int pipe_fds[2]; 246 unsigned char status = 1; 247 248 closefrom(0); 249 250 /* Open stdin/out/err, chdir, get a pipe */ 251 if (open("/dev/null", O_RDONLY) < 0 || 252 open("/dev/null", O_WRONLY) < 0 || dup(1) < 0 || 253 chdir("/") < 0 || pipe(pipe_fds) < 0) 254 exit(1); 255 256 /* For daemonize_ready() */ 257 write_pipe_fd = pipe_fds[1]; 258 259 switch (fork()) { 260 case -1: 261 exit(1); 262 /* NOTREACHED */ 263 case 0: 264 break; 265 default: 266 /* Wait for child to be ready befor exiting */ 267 (void) close(pipe_fds[1]); 268 (void) signal(SIGPIPE, SIG_DFL); 269 (void) read(pipe_fds[0], &status, sizeof (status)); 270 exit(status); 271 } 272 273 (void) close(pipe_fds[0]); 274 (void) setsid(); 275 } 276 277 static 278 void 279 daemonize_ready(unsigned char status) 280 { 281 if (write_pipe_fd == -1) 282 return; 283 284 (void) write(write_pipe_fd, &status, sizeof (status)); 285 (void) close(write_pipe_fd); 286 write_pipe_fd = -1; 287 } 288 289 /*ARGSUSED*/ 290 int 291 gssprog_1_freeresult(SVCXPRT *transport, xdrproc_t xdr_res, caddr_t res) 292 { 293 xdr_free(xdr_res, res); 294 return (1); 295 } 296