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