1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 /* appl/sample/sserver/sserver.c */ 3 /* 4 * Copyright 1990,1991 by the Massachusetts Institute of Technology. 5 * All Rights Reserved. 6 * 7 * Export of this software from the United States of America may 8 * require a specific license from the United States Government. 9 * It is the responsibility of any person or organization contemplating 10 * export to obtain such a license before exporting. 11 * 12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 13 * distribute this software and its documentation for any purpose and 14 * without fee is hereby granted, provided that the above copyright 15 * notice appear in all copies and that both that copyright notice and 16 * this permission notice appear in supporting documentation, and that 17 * the name of M.I.T. not be used in advertising or publicity pertaining 18 * to distribution of the software without specific, written prior 19 * permission. Furthermore if you modify this software you must label 20 * your software as modified software and not distribute it in such a 21 * fashion that it might be confused with the original M.I.T. software. 22 * M.I.T. makes no representations about the suitability of 23 * this software for any purpose. It is provided "as is" without express 24 * or implied warranty. 25 */ 26 27 /* 28 * Sample Kerberos v5 server. 29 * 30 * sample_server: 31 * A sample Kerberos server, which reads an AP_REQ from a TCP socket, 32 * decodes it, and writes back the results (in ASCII) to the client. 33 * 34 * Usage: 35 * sample_server servername 36 * 37 * file descriptor 0 (zero) should be a socket connected to the requesting 38 * client (this will be correct if this server is started by inetd). 39 */ 40 41 #include "k5-int.h" 42 #include "com_err.h" 43 44 #include <stdio.h> 45 #include <string.h> 46 #include <ctype.h> 47 #include <sys/types.h> 48 #include <sys/socket.h> 49 #include <netinet/in.h> 50 #include <netdb.h> 51 #include <syslog.h> 52 53 #ifdef HAVE_UNISTD_H 54 #include <unistd.h> 55 #endif 56 57 #include "../sample.h" 58 59 extern krb5_deltat krb5_clockskew; 60 61 #ifndef GETPEERNAME_ARG3_TYPE 62 #define GETPEERNAME_ARG3_TYPE int 63 #endif 64 65 static void 66 usage(char *name) 67 { 68 fprintf(stderr, "usage: %s [-p port] [-s service] [-S keytab]\n", 69 name); 70 } 71 72 int 73 main(int argc, char *argv[]) 74 { 75 krb5_context context; 76 krb5_auth_context auth_context = NULL; 77 krb5_ticket * ticket; 78 struct sockaddr_in peername; 79 GETPEERNAME_ARG3_TYPE namelen = sizeof(peername); 80 int sock = -1; /* incoming connection fd */ 81 krb5_data recv_data; 82 short xmitlen; 83 krb5_error_code retval; 84 krb5_principal server; 85 char repbuf[BUFSIZ]; 86 char *cname; 87 char *service = SAMPLE_SERVICE; 88 short port = 0; /* If user specifies port */ 89 extern int opterr, optind; 90 extern char * optarg; 91 int ch; 92 krb5_keytab keytab = NULL; /* Allow specification on command line */ 93 char *progname; 94 int on = 1; 95 96 progname = *argv; 97 98 retval = krb5_init_context(&context); 99 if (retval) { 100 com_err(argv[0], retval, "while initializing krb5"); 101 exit(1); 102 } 103 104 /* open a log connection */ 105 openlog("sserver", 0, LOG_DAEMON); 106 107 /* 108 * Parse command line arguments 109 * 110 */ 111 opterr = 0; 112 while ((ch = getopt(argc, argv, "p:S:s:")) != -1) { 113 switch (ch) { 114 case 'p': 115 port = atoi(optarg); 116 break; 117 case 's': 118 service = optarg; 119 break; 120 case 'S': 121 if ((retval = krb5_kt_resolve(context, optarg, &keytab))) { 122 com_err(progname, retval, 123 "while resolving keytab file %s", optarg); 124 exit(2); 125 } 126 break; 127 128 case '?': 129 default: 130 usage(progname); 131 exit(1); 132 break; 133 } 134 } 135 136 argc -= optind; 137 argv += optind; 138 139 /* Backwards compatibility, allow port to be specified at end */ 140 if (argc > 1) { 141 port = atoi(argv[1]); 142 } 143 144 retval = krb5_sname_to_principal(context, NULL, service, 145 KRB5_NT_SRV_HST, &server); 146 if (retval) { 147 syslog(LOG_ERR, "while generating service name (%s): %s", 148 service, error_message(retval)); 149 exit(1); 150 } 151 152 /* 153 * If user specified a port, then listen on that port; otherwise, 154 * assume we've been started out of inetd. 155 */ 156 157 if (port) { 158 int acc; 159 struct sockaddr_in sockin; 160 161 if ((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) { 162 syslog(LOG_ERR, "socket: %m"); 163 exit(3); 164 } 165 /* Let the socket be reused right away */ 166 (void) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, 167 sizeof(on)); 168 169 sockin.sin_family = AF_INET; 170 sockin.sin_addr.s_addr = 0; 171 sockin.sin_port = htons(port); 172 if (bind(sock, (struct sockaddr *) &sockin, sizeof(sockin))) { 173 syslog(LOG_ERR, "bind: %m"); 174 exit(3); 175 } 176 if (listen(sock, 1) == -1) { 177 syslog(LOG_ERR, "listen: %m"); 178 exit(3); 179 } 180 181 printf("starting...\n"); 182 fflush(stdout); 183 184 if ((acc = accept(sock, (struct sockaddr *)&peername, &namelen)) == -1){ 185 syslog(LOG_ERR, "accept: %m"); 186 exit(3); 187 } 188 dup2(acc, 0); 189 close(sock); 190 sock = 0; 191 } else { 192 /* 193 * To verify authenticity, we need to know the address of the 194 * client. 195 */ 196 if (getpeername(0, (struct sockaddr *)&peername, &namelen) < 0) { 197 syslog(LOG_ERR, "getpeername: %m"); 198 exit(1); 199 } 200 sock = 0; 201 } 202 203 retval = krb5_recvauth(context, &auth_context, (krb5_pointer)&sock, 204 SAMPLE_VERSION, server, 205 0, /* no flags */ 206 keytab, /* default keytab is NULL */ 207 &ticket); 208 if (retval) { 209 syslog(LOG_ERR, "recvauth failed--%s", error_message(retval)); 210 exit(1); 211 } 212 213 /* Get client name */ 214 repbuf[sizeof(repbuf) - 1] = '\0'; 215 retval = krb5_unparse_name(context, ticket->enc_part2->client, &cname); 216 if (retval){ 217 syslog(LOG_ERR, "unparse failed: %s", error_message(retval)); 218 strncpy(repbuf, "You are <unparse error>\n", sizeof(repbuf) - 1); 219 } else { 220 strncpy(repbuf, "You are ", sizeof(repbuf) - 1); 221 strncat(repbuf, cname, sizeof(repbuf) - 1 - strlen(repbuf)); 222 strncat(repbuf, "\n", sizeof(repbuf) - 1 - strlen(repbuf)); 223 free(cname); 224 } 225 xmitlen = htons(strlen(repbuf)); 226 recv_data.length = strlen(repbuf); 227 recv_data.data = repbuf; 228 if ((retval = krb5_net_write(context, 0, (char *)&xmitlen, 229 sizeof(xmitlen))) < 0) { 230 syslog(LOG_ERR, "%m: while writing len to client"); 231 exit(1); 232 } 233 if ((retval = krb5_net_write(context, 0, (char *)recv_data.data, 234 recv_data.length)) < 0) { 235 syslog(LOG_ERR, "%m: while writing data to client"); 236 exit(1); 237 } 238 239 krb5_free_ticket(context, ticket); 240 if(keytab) 241 krb5_kt_close(context, keytab); 242 krb5_free_principal(context, server); 243 krb5_auth_con_free(context, auth_context); 244 krb5_free_context(context); 245 exit(0); 246 } 247