1 /*
2  *  Copyright conserver.com, 2000
3  *
4  *  Maintainer/Enhancer: Bryan Stansell (bryan@conserver.com)
5  *
6  *  Copyright GNAC, Inc., 1998
7  */
8 
9 /*
10  * Copyright (c) 1990 The Ohio State University.
11  * All rights reserved.
12  *
13  * Redistribution and use in source and binary forms are permitted
14  * provided that: (1) source distributions retain this entire copyright
15  * notice and comment, and (2) distributions including binaries display
16  * the following acknowledgement:  ``This product includes software
17  * developed by The Ohio State University and its contributors''
18  * in the documentation or other materials provided with the distribution
19  * and in all advertising materials mentioning features or use of this
20  * software. Neither the name of the University nor the names of its
21  * contributors may be used to endorse or promote products derived
22  * from this software without specific prior written permission.
23  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
24  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
25  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
26  */
27 
28 #include <compat.h>
29 
30 #include <pwd.h>
31 
32 #include <cutil.h>
33 #include <consent.h>
34 #include <client.h>
35 #include <group.h>
36 #include <access.h>
37 #include <master.h>
38 #include <readcfg.h>
39 #include <version.h>
40 
41 #include <dirent.h>
42 #if HAVE_OPENSSL
43 # include <openssl/opensslv.h>
44 #endif
45 #if HAVE_GSSAPI
46 # include <gssapi/gssapi.h>
47 #endif
48 
49 
50 int fAll = 0, fNoinit = 0, fVersion = 0, fStrip = 0, fReopen =
51     0, fNoautoreup = 0, fSyntaxOnly = 0;
52 
53 char *pcConfig = CONFIGFILE;
54 int cMaxMemb = MAXMEMB;
55 #if USE_IPV6
56 struct addrinfo *bindAddr;
57 struct addrinfo *bindBaseAddr;
58 #else
59 in_addr_t bindAddr = INADDR_ANY;
60 unsigned short bindPort;
61 unsigned short bindBasePort;
62 struct sockaddr_in in_port;
63 #endif
64 static STRING *startedMsg = (STRING *)0;
65 CONFIG *optConf = (CONFIG *)0;
66 CONFIG *config = (CONFIG *)0;
67 char *interface = (char *)0;
68 CONFIG defConfig =
69     { (STRING *)0, FLAGTRUE, 'r', FLAGFALSE, LOGFILEPATH, PASSWDFILE,
70     DEFPORT,
71     FLAGTRUE, FLAGTRUE, 0, DEFBASEPORT, (char *)0, 0
72 #if HAVE_SETPROCTITLE
73 	, FLAGFALSE
74 #endif
75 #if HAVE_OPENSSL
76 	, (char *)0, FLAGTRUE, FLAGFALSE, (char *)0
77 #endif
78 };
79 
80 CONSFILE *unifiedlog = (CONSFILE *)0;
81 
82 #if HAVE_DMALLOC && DMALLOC_MARK_MAIN
83 unsigned long dmallocMarkMain = 0;
84 #endif
85 
86 #if HAVE_OPENSSL
87 # if OPENSSL_VERSION_NUMBER < 0x10100000L
88 int
DH_set0_pqg(DH * dh,BIGNUM * p,BIGNUM * q,BIGNUM * g)89 DH_set0_pqg(DH *dh, BIGNUM * p, BIGNUM * q, BIGNUM * g)
90 {
91     /* If the fields p and g in d are NULL, the corresponding input
92      * parameters MUST be non-NULL.  q may remain NULL.
93      */
94     if ((dh->p == NULL && p == NULL)
95 	|| (dh->g == NULL && g == NULL))
96 	return 0;
97 
98     if (p != NULL) {
99 	BN_free(dh->p);
100 	dh->p = p;
101     }
102     if (q != NULL) {
103 	BN_free(dh->q);
104 	dh->q = q;
105     }
106     if (g != NULL) {
107 	BN_free(dh->g);
108 	dh->g = g;
109     }
110 
111     if (q != NULL) {
112 	dh->length = BN_num_bits(q);
113     }
114 
115     return 1;
116 }
117 # endif/* OPENSSL_VERSION_NUMBER < 0x10100000L */
118 
119 SSL_CTX *ctx = (SSL_CTX *)0;
120 DH *dh512 = (DH *)0;
121 DH *dh1024 = (DH *)0;
122 DH *dh2048 = (DH *)0;
123 DH *dh4096 = (DH *)0;
124 
125 DH *
DHFromArray(unsigned char * dh_p,size_t dh_p_size,unsigned char * dh_g,size_t dh_g_size)126 DHFromArray(unsigned char *dh_p, size_t dh_p_size, unsigned char *dh_g,
127 	    size_t dh_g_size)
128 {
129     DH *dh;
130     BIGNUM *p, *g;
131 
132     p = BN_bin2bn(dh_p, dh_p_size, NULL);
133     if (p == NULL) {
134 	return (NULL);
135     }
136 
137     g = BN_bin2bn(dh_g, dh_g_size, NULL);
138     if (g == NULL) {
139 	BN_free(g);
140 	return (NULL);
141     }
142 
143     if ((dh = DH_new()) == NULL) {
144 	BN_free(p);
145 	BN_free(g);
146 	return (NULL);
147     }
148 
149     if (!DH_set0_pqg(dh, p, NULL, g)) {
150 	BN_free(p);
151 	BN_free(g);
152 	DH_free(dh);
153 	return (NULL);
154     }
155 
156     return (dh);
157 }
158 
159 DH *
GetDH512(void)160 GetDH512(void)
161 {
162     static unsigned char dh512_p[] = {
163 	0xF5, 0x2A, 0xFF, 0x3C, 0xE1, 0xB1, 0x29, 0x40, 0x18, 0x11, 0x8D,
164 	0x7C, 0x84, 0xA7, 0x0A, 0x72, 0xD6, 0x86, 0xC4, 0x03, 0x19,
165 	0xC8, 0x07, 0x29, 0x7A, 0xCA, 0x95, 0x0C, 0xD9, 0x96, 0x9F,
166 	0xAB, 0xD0, 0x0A, 0x50, 0x9B, 0x02, 0x46, 0xD3, 0x08, 0x3D,
167 	0x66, 0xA4, 0x5D, 0x41, 0x9F, 0x9C, 0x7C, 0xBD, 0x89, 0x4B,
168 	0x22, 0x19, 0x26, 0xBA, 0xAB, 0xA2, 0x5E, 0xC3, 0x55, 0xE9,
169 	0x2A, 0x05, 0x5F,
170     };
171     static unsigned char dh512_g[] = {
172 	0x02,
173     };
174 
175     return DHFromArray(dh512_p, sizeof(dh512_p), dh512_g, sizeof(dh512_g));
176 }
177 
178 DH *
GetDH1024(void)179 GetDH1024(void)
180 {
181     static unsigned char dh1024_p[] = {
182 	0xF4, 0x88, 0xFD, 0x58, 0x4E, 0x49, 0xDB, 0xCD, 0x20, 0xB4, 0x9D,
183 	0xE4, 0x91, 0x07, 0x36, 0x6B, 0x33, 0x6C, 0x38, 0x0D, 0x45,
184 	0x1D, 0x0F, 0x7C, 0x88, 0xB3, 0x1C, 0x7C, 0x5B, 0x2D, 0x8E,
185 	0xF6, 0xF3, 0xC9, 0x23, 0xC0, 0x43, 0xF0, 0xA5, 0x5B, 0x18,
186 	0x8D, 0x8E, 0xBB, 0x55, 0x8C, 0xB8, 0x5D, 0x38, 0xD3, 0x34,
187 	0xFD, 0x7C, 0x17, 0x57, 0x43, 0xA3, 0x1D, 0x18, 0x6C, 0xDE,
188 	0x33, 0x21, 0x2C, 0xB5, 0x2A, 0xFF, 0x3C, 0xE1, 0xB1, 0x29,
189 	0x40, 0x18, 0x11, 0x8D, 0x7C, 0x84, 0xA7, 0x0A, 0x72, 0xD6,
190 	0x86, 0xC4, 0x03, 0x19, 0xC8, 0x07, 0x29, 0x7A, 0xCA, 0x95,
191 	0x0C, 0xD9, 0x96, 0x9F, 0xAB, 0xD0, 0x0A, 0x50, 0x9B, 0x02,
192 	0x46, 0xD3, 0x08, 0x3D, 0x66, 0xA4, 0x5D, 0x41, 0x9F, 0x9C,
193 	0x7C, 0xBD, 0x89, 0x4B, 0x22, 0x19, 0x26, 0xBA, 0xAB, 0xA2,
194 	0x5E, 0xC3, 0x55, 0xE9, 0x2F, 0x78, 0xC7,
195     };
196     static unsigned char dh1024_g[] = {
197 	0x02,
198     };
199 
200     return DHFromArray(dh1024_p, sizeof(dh1024_p), dh1024_g,
201 		       sizeof(dh1024_g));
202 }
203 
204 DH *
GetDH2048(void)205 GetDH2048(void)
206 {
207     static unsigned char dh2048_p[] = {
208 	0xF6, 0x42, 0x57, 0xB7, 0x08, 0x7F, 0x08, 0x17, 0x72, 0xA2, 0xBA,
209 	0xD6, 0xA9, 0x42, 0xF3, 0x05, 0xE8, 0xF9, 0x53, 0x11, 0x39,
210 	0x4F, 0xB6, 0xF1, 0x6E, 0xB9, 0x4B, 0x38, 0x20, 0xDA, 0x01,
211 	0xA7, 0x56, 0xA3, 0x14, 0xE9, 0x8F, 0x40, 0x55, 0xF3, 0xD0,
212 	0x07, 0xC6, 0xCB, 0x43, 0xA9, 0x94, 0xAD, 0xF7, 0x4C, 0x64,
213 	0x86, 0x49, 0xF8, 0x0C, 0x83, 0xBD, 0x65, 0xE9, 0x17, 0xD4,
214 	0xA1, 0xD3, 0x50, 0xF8, 0xF5, 0x59, 0x5F, 0xDC, 0x76, 0x52,
215 	0x4F, 0x3D, 0x3D, 0x8D, 0xDB, 0xCE, 0x99, 0xE1, 0x57, 0x92,
216 	0x59, 0xCD, 0xFD, 0xB8, 0xAE, 0x74, 0x4F, 0xC5, 0xFC, 0x76,
217 	0xBC, 0x83, 0xC5, 0x47, 0x30, 0x61, 0xCE, 0x7C, 0xC9, 0x66,
218 	0xFF, 0x15, 0xF9, 0xBB, 0xFD, 0x91, 0x5E, 0xC7, 0x01, 0xAA,
219 	0xD3, 0x5B, 0x9E, 0x8D, 0xA0, 0xA5, 0x72, 0x3A, 0xD4, 0x1A,
220 	0xF0, 0xBF, 0x46, 0x00, 0x58, 0x2B, 0xE5, 0xF4, 0x88, 0xFD,
221 	0x58, 0x4E, 0x49, 0xDB, 0xCD, 0x20, 0xB4, 0x9D, 0xE4, 0x91,
222 	0x07, 0x36, 0x6B, 0x33, 0x6C, 0x38, 0x0D, 0x45, 0x1D, 0x0F,
223 	0x7C, 0x88, 0xB3, 0x1C, 0x7C, 0x5B, 0x2D, 0x8E, 0xF6, 0xF3,
224 	0xC9, 0x23, 0xC0, 0x43, 0xF0, 0xA5, 0x5B, 0x18, 0x8D, 0x8E,
225 	0xBB, 0x55, 0x8C, 0xB8, 0x5D, 0x38, 0xD3, 0x34, 0xFD, 0x7C,
226 	0x17, 0x57, 0x43, 0xA3, 0x1D, 0x18, 0x6C, 0xDE, 0x33, 0x21,
227 	0x2C, 0xB5, 0x2A, 0xFF, 0x3C, 0xE1, 0xB1, 0x29, 0x40, 0x18,
228 	0x11, 0x8D, 0x7C, 0x84, 0xA7, 0x0A, 0x72, 0xD6, 0x86, 0xC4,
229 	0x03, 0x19, 0xC8, 0x07, 0x29, 0x7A, 0xCA, 0x95, 0x0C, 0xD9,
230 	0x96, 0x9F, 0xAB, 0xD0, 0x0A, 0x50, 0x9B, 0x02, 0x46, 0xD3,
231 	0x08, 0x3D, 0x66, 0xA4, 0x5D, 0x41, 0x9F, 0x9C, 0x7C, 0xBD,
232 	0x89, 0x4B, 0x22, 0x19, 0x26, 0xBA, 0xAB, 0xA2, 0x5E, 0xC3,
233 	0x55, 0xE9, 0x32, 0x0B, 0x3B,
234     };
235     static unsigned char dh2048_g[] = {
236 	0x02,
237     };
238 
239     return DHFromArray(dh2048_p, sizeof(dh2048_p), dh2048_g,
240 		       sizeof(dh2048_g));
241 }
242 
243 DH *
GetDH4096(void)244 GetDH4096(void)
245 {
246     static unsigned char dh4096_p[] = {
247 	0xFA, 0x14, 0x72, 0x52, 0xC1, 0x4D, 0xE1, 0x5A, 0x49, 0xD4, 0xEF,
248 	0x09, 0x2D, 0xC0, 0xA8, 0xFD, 0x55, 0xAB, 0xD7, 0xD9, 0x37,
249 	0x04, 0x28, 0x09, 0xE2, 0xE9, 0x3E, 0x77, 0xE2, 0xA1, 0x7A,
250 	0x18, 0xDD, 0x46, 0xA3, 0x43, 0x37, 0x23, 0x90, 0x97, 0xF3,
251 	0x0E, 0xC9, 0x03, 0x50, 0x7D, 0x65, 0xCF, 0x78, 0x62, 0xA6,
252 	0x3A, 0x62, 0x22, 0x83, 0xA1, 0x2F, 0xFE, 0x79, 0xBA, 0x35,
253 	0xFF, 0x59, 0xD8, 0x1D, 0x61, 0xDD, 0x1E, 0x21, 0x13, 0x17,
254 	0xFE, 0xCD, 0x38, 0x87, 0x9E, 0xF5, 0x4F, 0x79, 0x10, 0x61,
255 	0x8D, 0xD4, 0x22, 0xF3, 0x5A, 0xED, 0x5D, 0xEA, 0x21, 0xE9,
256 	0x33, 0x6B, 0x48, 0x12, 0x0A, 0x20, 0x77, 0xD4, 0x25, 0x60,
257 	0x61, 0xDE, 0xF6, 0xB4, 0x4F, 0x1C, 0x63, 0x40, 0x8B, 0x3A,
258 	0x21, 0x93, 0x8B, 0x79, 0x53, 0x51, 0x2C, 0xCA, 0xB3, 0x7B,
259 	0x29, 0x56, 0xA8, 0xC7, 0xF8, 0xF4, 0x7B, 0x08, 0x5E, 0xA6,
260 	0xDC, 0xA2, 0x45, 0x12, 0x56, 0xDD, 0x41, 0x92, 0xF2, 0xDD,
261 	0x5B, 0x8F, 0x23, 0xF0, 0xF3, 0xEF, 0xE4, 0x3B, 0x0A, 0x44,
262 	0xDD, 0xED, 0x96, 0x84, 0xF1, 0xA8, 0x32, 0x46, 0xA3, 0xDB,
263 	0x4A, 0xBE, 0x3D, 0x45, 0xBA, 0x4E, 0xF8, 0x03, 0xE5, 0xDD,
264 	0x6B, 0x59, 0x0D, 0x84, 0x1E, 0xCA, 0x16, 0x5A, 0x8C, 0xC8,
265 	0xDF, 0x7C, 0x54, 0x44, 0xC4, 0x27, 0xA7, 0x3B, 0x2A, 0x97,
266 	0xCE, 0xA3, 0x7D, 0x26, 0x9C, 0xAD, 0xF4, 0xC2, 0xAC, 0x37,
267 	0x4B, 0xC3, 0xAD, 0x68, 0x84, 0x7F, 0x99, 0xA6, 0x17, 0xEF,
268 	0x6B, 0x46, 0x3A, 0x7A, 0x36, 0x7A, 0x11, 0x43, 0x92, 0xAD,
269 	0xE9, 0x9C, 0xFB, 0x44, 0x6C, 0x3D, 0x82, 0x49, 0xCC, 0x5C,
270 	0x6A, 0x52, 0x42, 0xF8, 0x42, 0xFB, 0x44, 0xF9, 0x39, 0x73,
271 	0xFB, 0x60, 0x79, 0x3B, 0xC2, 0x9E, 0x0B, 0xDC, 0xD4, 0xA6,
272 	0x67, 0xF7, 0x66, 0x3F, 0xFC, 0x42, 0x3B, 0x1B, 0xDB, 0x4F,
273 	0x66, 0xDC, 0xA5, 0x8F, 0x66, 0xF9, 0xEA, 0xC1, 0xED, 0x31,
274 	0xFB, 0x48, 0xA1, 0x82, 0x7D, 0xF8, 0xE0, 0xCC, 0xB1, 0xC7,
275 	0x03, 0xE4, 0xF8, 0xB3, 0xFE, 0xB7, 0xA3, 0x13, 0x73, 0xA6,
276 	0x7B, 0xC1, 0x0E, 0x39, 0xC7, 0x94, 0x48, 0x26, 0x00, 0x85,
277 	0x79, 0xFC, 0x6F, 0x7A, 0xAF, 0xC5, 0x52, 0x35, 0x75, 0xD7,
278 	0x75, 0xA4, 0x40, 0xFA, 0x14, 0x74, 0x61, 0x16, 0xF2, 0xEB,
279 	0x67, 0x11, 0x6F, 0x04, 0x43, 0x3D, 0x11, 0x14, 0x4C, 0xA7,
280 	0x94, 0x2A, 0x39, 0xA1, 0xC9, 0x90, 0xCF, 0x83, 0xC6, 0xFF,
281 	0x02, 0x8F, 0xA3, 0x2A, 0xAC, 0x26, 0xDF, 0x0B, 0x8B, 0xBE,
282 	0x64, 0x4A, 0xF1, 0xA1, 0xDC, 0xEE, 0xBA, 0xC8, 0x03, 0x82,
283 	0xF6, 0x62, 0x2C, 0x5D, 0xB6, 0xBB, 0x13, 0x19, 0x6E, 0x86,
284 	0xC5, 0x5B, 0x2B, 0x5E, 0x3A, 0xF3, 0xB3, 0x28, 0x6B, 0x70,
285 	0x71, 0x3A, 0x8E, 0xFF, 0x5C, 0x15, 0xE6, 0x02, 0xA4, 0xCE,
286 	0xED, 0x59, 0x56, 0xCC, 0x15, 0x51, 0x07, 0x79, 0x1A, 0x0F,
287 	0x25, 0x26, 0x27, 0x30, 0xA9, 0x15, 0xB2, 0xC8, 0xD4, 0x5C,
288 	0xCC, 0x30, 0xE8, 0x1B, 0xD8, 0xD5, 0x0F, 0x19, 0xA8, 0x80,
289 	0xA4, 0xC7, 0x01, 0xAA, 0x8B, 0xBA, 0x53, 0xBB, 0x47, 0xC2,
290 	0x1F, 0x6B, 0x54, 0xB0, 0x17, 0x60, 0xED, 0x79, 0x21, 0x95,
291 	0xB6, 0x05, 0x84, 0x37, 0xC8, 0x03, 0xA4, 0xDD, 0xD1, 0x06,
292 	0x69, 0x8F, 0x4C, 0x39, 0xE0, 0xC8, 0x5D, 0x83, 0x1D, 0xBE,
293 	0x6A, 0x9A, 0x99, 0xF3, 0x9F, 0x0B, 0x45, 0x29, 0xD4, 0xCB,
294 	0x29, 0x66, 0xEE, 0x1E, 0x7E, 0x3D, 0xD7, 0x13, 0x4E, 0xDB,
295 	0x90, 0x90, 0x58, 0xCB, 0x5E, 0x9B, 0xCD, 0x2E, 0x2B, 0x0F,
296 	0xA9, 0x4E, 0x78, 0xAC, 0x05, 0x11, 0x7F, 0xE3, 0x9E, 0x27,
297 	0xD4, 0x99, 0xE1, 0xB9, 0xBD, 0x78, 0xE1, 0x84, 0x41, 0xA0,
298 	0xDF,
299     };
300     static unsigned char dh4096_g[] = {
301 	0x02,
302     };
303 
304     return DHFromArray(dh4096_p, sizeof(dh4096_p), dh4096_g,
305 		       sizeof(dh4096_g));
306 }
307 
308 DH *
TmpDHCallback(SSL * ssl,int is_export,int keylength)309 TmpDHCallback(SSL *ssl, int is_export, int keylength)
310 {
311     CONDDEBUG((1, "TmpDHCallback(): asked for a DH key length %u",
312 	       keylength));
313     switch (keylength) {
314 	case 512:
315 	    if (dh512 == (DH *)0)
316 		dh512 = GetDH512();
317 	    return dh512;
318 	case 1024:
319 	    if (dh1024 == (DH *)0)
320 		dh1024 = GetDH1024();
321 	    return dh1024;
322 	case 2048:
323 	    if (dh2048 == (DH *)0)
324 		dh2048 = GetDH2048();
325 	    return dh2048;
326 	default:
327 	    if (dh4096 == (DH *)0)
328 		dh4096 = GetDH4096();
329 	    return dh4096;
330     }
331 }
332 
333 void
SetupSSL(void)334 SetupSSL(void)
335 {
336     if (ctx == (SSL_CTX *)0) {
337 	char *ciphers;
338 	int verifymode;
339 # if OPENSSL_VERSION_NUMBER < 0x10100000L
340 	SSL_load_error_strings();
341 	if (!SSL_library_init()) {
342 	    Error("SetupSSL(): SSL_library_init() failed");
343 	    Bye(EX_SOFTWARE);
344 	}
345 # endif/* OPENSSL_VERSION_NUMBER < 0x10100000L */
346 	if ((ctx = SSL_CTX_new(TLS_method())) == (SSL_CTX *)0) {
347 	    Error("SetupSSL(): SSL_CTX_new() failed");
348 	    Bye(EX_SOFTWARE);
349 	}
350 	if (SSL_CTX_set_default_verify_paths(ctx) != 1) {
351 	    Error
352 		("SetupSSL(): could not load SSL default CA file and/or directory");
353 	    Bye(EX_SOFTWARE);
354 	}
355 	if (config->sslcredentials != (char *)0) {
356 	    if (SSL_CTX_use_certificate_chain_file
357 		(ctx, config->sslcredentials) != 1) {
358 		Error
359 		    ("SetupSSL(): could not load SSL certificate from `%s'",
360 		     config->sslcredentials);
361 		Bye(EX_SOFTWARE);
362 	    }
363 	    if (SSL_CTX_use_PrivateKey_file
364 		(ctx, config->sslcredentials, SSL_FILETYPE_PEM) != 1) {
365 		Error
366 		    ("SetupSSL(): could not load SSL private key from `%s'",
367 		     config->sslcredentials);
368 		Bye(EX_SOFTWARE);
369 	    }
370 	    ciphers = "ALL:!LOW:!EXP:!MD5:!aNULL:@STRENGTH";
371 	} else {
372 	    ciphers = "ALL:aNULL:!LOW:!EXP:!MD5:@STRENGTH" CIPHER_SEC0;
373 	}
374 	if (config->sslcacertificatefile != (char *)0) {
375 	    STACK_OF(X509_NAME) * cert_names;
376 
377 	    cert_names =
378 		SSL_load_client_CA_file(config->sslcacertificatefile);
379 	    if (cert_names != NULL) {
380 		SSL_CTX_set_client_CA_list(ctx, cert_names);
381 		if (SSL_CTX_load_verify_locations
382 		    (ctx, config->sslcacertificatefile, NULL) != 1) {
383 		    Error("Could not setup CA certificate file to '%s'",
384 			  config->sslcacertificatefile);
385 		    Bye(EX_UNAVAILABLE);
386 		}
387 	    } else {
388 		Error
389 		    ("SetupSSL(): could not load SSL client CA list from `%s'",
390 		     config->sslcacertificatefile);
391 		Bye(EX_SOFTWARE);
392 	    }
393 	}
394 
395 	verifymode = SSL_VERIFY_PEER;
396 	if (config->sslreqclientcert == FLAGTRUE)
397 	    verifymode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
398 	SSL_CTX_set_verify(ctx, verifymode, SSLVerifyCallback);
399 	SSL_CTX_set_options(ctx,
400 			    SSL_OP_ALL | SSL_OP_NO_SSLv2 |
401 			    SSL_OP_SINGLE_DH_USE);
402 	SSL_CTX_set_mode(ctx,
403 			 SSL_MODE_ENABLE_PARTIAL_WRITE |
404 			 SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER |
405 			 SSL_MODE_AUTO_RETRY);
406 	SSL_CTX_set_tmp_dh_callback(ctx, TmpDHCallback);
407 	if (SSL_CTX_set_cipher_list(ctx, ciphers) != 1) {
408 	    Error("SetupSSL(): setting SSL cipher list failed");
409 	    Bye(EX_SOFTWARE);
410 	}
411 	/* might want to turn this back on at some point, but i can't
412 	 * see why right now.
413 	 */
414 	SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
415     }
416 }
417 #endif
418 
419 #if HAVE_GSSAPI
420 gss_name_t gss_myname = GSS_C_NO_NAME;
421 gss_cred_id_t gss_mycreds = GSS_C_NO_CREDENTIAL;
422 
423 void
SetupGSSAPI(void)424 SetupGSSAPI(void)
425 {
426     OM_uint32 stmaj, stmin;
427     char namestr[128];
428     gss_buffer_desc namebuf;
429 
430     snprintf(namestr, 128, "host@%s", myHostname);
431     namebuf.value = namestr;
432     namebuf.length = strlen(namestr) + 1;
433     stmaj =
434 	gss_import_name(&stmin, &namebuf, GSS_C_NT_HOSTBASED_SERVICE,
435 			&gss_myname);
436     /* XXX: handle error */
437     if (stmaj != GSS_S_COMPLETE) {
438 	Error("gss_import_name failed");
439     }
440     /* Get some initial credentials */
441     stmaj =
442 	gss_acquire_cred(&stmin, gss_myname, 0, GSS_C_NULL_OID_SET,
443 			 GSS_C_ACCEPT, &gss_mycreds, NULL, NULL);
444     if (stmaj != GSS_S_COMPLETE) {
445 	Error("Could not acquire GSS-API credentials");
446     }
447 
448 }
449 #endif
450 
451 void
ReopenLogfile(void)452 ReopenLogfile(void)
453 {
454     static int tag = 1;
455     /* redirect stdout and stderr to the logfile.
456      *
457      * first time through any problems will show up (stderr still there).
458      * after that, all bets are off...probably not see the errors (well,
459      * aside from the tail of the old logfile, if it was rolled).
460      */
461     if (config->daemonmode != FLAGTRUE)
462 	return;
463 
464     close(1);
465 
466     /* so, if we aren't in daemon mode, we just return before closing
467      * anything.  if we are, there are two possibilities.  first, if
468      * logfile is set, we close fd 1, open a file, etc.  all should be
469      * well.  if logfile isn't set, we end up closing fd 1 and 2 and
470      * returning (in case the logfile was set and then unset [config
471      * file change]).
472      */
473     if (config->logfile == (char *)0) {
474 	close(2);
475 	return;
476     }
477 
478     if (1 != open(config->logfile, O_WRONLY | O_CREAT | O_APPEND, 0644)) {
479 	tag = 0;
480 	Error("ReopenLogfile(): open(%s): %s", config->logfile,
481 	      strerror(errno));
482 	Bye(EX_TEMPFAIL);
483     }
484     close(2);
485     dup(1);
486     if (isMaster && tag) {
487 	Msg(MyVersion());
488 	Msg(startedMsg->string);
489     }
490     tag = 0;
491 }
492 
493 void
ReopenUnifiedlog(void)494 ReopenUnifiedlog(void)
495 {
496     /* close any existing */
497     if (unifiedlog != (CONSFILE *)0)
498 	FileClose(&unifiedlog);
499 
500     /* return if we aren't opening again */
501     if (config->unifiedlog == (char *)0)
502 	return;
503 
504     /* open a new one */
505     if ((unifiedlog =
506 	 FileOpen(config->unifiedlog, O_WRONLY | O_CREAT | O_APPEND,
507 		  0644)) == (CONSFILE *)0) {
508 	Error("ReopenUnifiedlog(): open(%s): %s", config->unifiedlog,
509 	      strerror(errno));
510 	return;
511     }
512 }
513 
514 /* become a daemon							(ksb)
515  */
516 static void
Daemonize(void)517 Daemonize(void)
518 {
519     int res;
520 #if !HAVE_SETSID
521     int td;
522 #endif
523 
524     Msg("daemonizing");
525     SimpleSignal(SIGQUIT, SIG_IGN);
526     SimpleSignal(SIGINT, SIG_IGN);
527 #if defined(SIGTTOU)
528     SimpleSignal(SIGTTOU, SIG_IGN);
529 #endif
530 #if defined(SIGTTIN)
531     SimpleSignal(SIGTTIN, SIG_IGN);
532 #endif
533 #if defined(SIGTSTP)
534     SimpleSignal(SIGTSTP, SIG_IGN);
535 #endif
536 #if defined(SIGXFSZ)
537     SimpleSignal(SIGXFSZ, SIG_IGN);
538 #endif
539 
540     fflush(stdout);
541     fflush(stderr);
542 
543     switch (res = fork()) {
544 	case -1:
545 	    Error("Daemonize(): fork(): %s", strerror(errno));
546 	    Bye(EX_TEMPFAIL);
547 	case 0:
548 	    thepid = getpid();
549 	    break;
550 	default:
551 	    Bye(EX_OK);
552     }
553 
554     ReopenLogfile();
555 
556     /* Further disassociate this process from the terminal
557      * Maybe this will allow you to start a daemon from rsh,
558      * i.e. with no controlling terminal.
559      */
560 #if HAVE_SETSID
561     setsid();
562 #else
563     tcsetpgrp(0, getpid());
564 
565     /* lose our controlling terminal
566      */
567     if (-1 != (td = open("/dev/tty", O_RDWR, 0600))) {
568 	ioctl(td, TIOCNOTTY, (char *)0);
569 	close(td);
570     }
571 #endif
572 }
573 
574 
575 /* output a long message to the user					(ksb)
576  */
577 static void
Usage(int wantfull)578 Usage(int wantfull)
579 {
580     static char u_terse[] =
581 	"[-7dDEFhinoRSuvV] [-a type] [-m max] [-M master] [-p port] [-b port] [-c cred] [-C config] [-P passwd] [-L logfile] [-O min] [-U logfile]";
582     static char *full[] = {
583 	"7          strip the high bit off all console data",
584 	"a type     set the default access type",
585 	"b port     base port for secondary channel (any by default)",
586 #if HAVE_OPENSSL
587 	"c cred     load an SSL certificate and key from the PEM encoded file",
588 #else
589 	"c cred     ignored - encryption not compiled into code",
590 #endif
591 	"C config   give a new config file to the server process",
592 	"d          become a daemon, redirecting stdout/stderr to logfile",
593 	"D          enable debug output, sent to stderr",
594 #if HAVE_OPENSSL
595 	"E          don't require encrypted client connections",
596 #else
597 	"E          ignored - encryption not compiled into code",
598 #endif
599 	"F          do not automatically reinitialize failed consoles",
600 	"h          output this message",
601 	"i          initialize console connections on demand",
602 	"L logfile  give a new logfile path to the server process",
603 	"m max      maximum consoles managed per process",
604 #if USE_UNIX_DOMAIN_SOCKETS
605 	"M master   directory that holds the Unix domain sockets",
606 #else
607 	"M master   address to listen on (all addresses by default)",
608 #endif
609 	"n          obsolete - see -u",
610 	"o          reopen downed console on client connect",
611 	"O min      reopen all downed consoles every <min> minutes",
612 #if USE_UNIX_DOMAIN_SOCKETS
613 	"p port     ignored - Unix domain sockets compiled into code",
614 #else
615 	"p port     port to listen on",
616 #endif
617 	"P passwd   give a new passwd file to the server process",
618 	"R          disable automatic client redirection",
619 	"S          syntax check of configuration file",
620 	"u          copy \"unloved\" console data to stdout",
621 	"U logfile  copy all console data to the \"unified\" logfile",
622 	"v          be verbose on startup",
623 	"V          output version info",
624 	(char *)0
625     };
626     fprintf(stderr, "usage: %s %s\n", progname, u_terse);
627     if (wantfull) {
628 	int i;
629 	for (i = 0; full[i] != (char *)0; i++)
630 	    fprintf(stderr, "\t%s\n", full[i]);
631     }
632 }
633 
634 /* show the user our version info					(ksb)
635  */
636 static void
Version(void)637 Version(void)
638 {
639     static STRING *acA1 = (STRING *)0;
640     static STRING *acA2 = (STRING *)0;
641     int i;
642     char *optionlist[] = {
643 #if HAVE_DMALLOC
644 	"dmalloc",
645 #endif
646 #if HAVE_FREEIPMI
647 	"freeipmi",
648 #endif
649 #if USE_LIBWRAP
650 	"libwrap",
651 #endif
652 #if HAVE_OPENSSL
653 	"openssl",
654 #endif
655 #if HAVE_PAM
656 	"pam",
657 #endif
658 #if TRUST_REVERSE_DNS
659 	"trustrevdns",
660 #endif
661 #if USE_UNIX_DOMAIN_SOCKETS
662 	"uds",
663 #endif
664 	(char *)0
665     };
666 
667     if (acA1 == (STRING *)0)
668 	acA1 = AllocString();
669     if (acA2 == (STRING *)0)
670 	acA2 = AllocString();
671 
672     isMultiProc = 0;
673 
674     Msg(MyVersion());
675     Msg("default access type `%c'", defConfig.defaultaccess);
676     Msg("default escape sequence `%s%s'", FmtCtl(DEFATTN, acA1),
677 	FmtCtl(DEFESC, acA2));
678     Msg("default configuration in `%s'", CONFIGFILE);
679     Msg("default password in `%s'", defConfig.passwdfile);
680     Msg("default logfile is `%s'", defConfig.logfile);
681     Msg("default pidfile is `%s'", PIDFILE);
682     Msg("default limit is %d member%s per group", MAXMEMB,
683 	MAXMEMB == 1 ? "" : "s");
684 #if USE_UNIX_DOMAIN_SOCKETS
685     Msg("default socket directory `%s'", UDSDIR);
686 #else
687     Msg("default primary port referenced as `%s'", defConfig.primaryport);
688     Msg("default secondary base port referenced as `%s'",
689 	defConfig.secondaryport);
690 #endif
691 
692     BuildString((char *)0, acA1);
693     if (optionlist[0] == (char *)0)
694 	BuildString("none", acA1);
695     for (i = 0; optionlist[i] != (char *)0; i++) {
696 	if (i == 0)
697 	    BuildString(optionlist[i], acA1);
698 	else {
699 	    BuildString(", ", acA1);
700 	    BuildString(optionlist[i], acA1);
701 	}
702     }
703     Msg("options: %s", acA1->string);
704 #if HAVE_DMALLOC
705     BuildString((char *)0, acA1);
706     BuildStringChar('0' + DMALLOC_VERSION_MAJOR, acA1);
707     BuildStringChar('.', acA1);
708     BuildStringChar('0' + DMALLOC_VERSION_MINOR, acA1);
709     BuildStringChar('.', acA1);
710     BuildStringChar('0' + DMALLOC_VERSION_PATCH, acA1);
711 # if defined(DMALLOC_VERSION_BETA)
712     if (DMALLOC_VERSION_BETA != 0) {
713 	BuildString("-b", acA1);
714 	BuildStringChar('0' + DMALLOC_VERSION_BETA, acA1);
715     }
716 # endif
717     Msg("dmalloc version: %s", acA1->string);
718 #endif
719 #if HAVE_FREEIPMI
720     BuildString((char *)0, acA1);
721     BuildStringChar('0' + LIBIPMICONSOLE_VERSION_MAJOR, acA1);
722     BuildStringChar('.', acA1);
723     BuildStringChar('0' + LIBIPMICONSOLE_VERSION_MINOR, acA1);
724     BuildStringChar('.', acA1);
725     BuildStringChar('0' + LIBIPMICONSOLE_VERSION_PATCH, acA1);
726     Msg("freeipmi version: %s", acA1->string);
727 #endif
728 #if HAVE_OPENSSL
729     Msg("openssl version: %s", OPENSSL_VERSION_TEXT);
730 #endif
731     Msg("built with `%s'", CONFIGINVOCATION);
732 
733     if (fVerbose)
734 	printf(COPYRIGHT);
735     Bye(EX_OK);
736 }
737 
738 void
DestroyDataStructures(void)739 DestroyDataStructures(void)
740 {
741     GRPENT *pGE;
742     REMOTE *pRC;
743     ACCESS *pAC;
744 
745     while (pGroups != (GRPENT *)0) {
746 	pGE = pGroups->pGEnext;
747 	DestroyGroup(pGroups);
748 	pGroups = pGE;
749     }
750 
751     while (pRCList != (REMOTE *)0) {
752 	pRC = pRCList->pRCnext;
753 	DestroyRemoteConsole(pRCList);
754 	pRCList = pRC;
755     }
756 
757     while (pACList != (ACCESS *)0) {
758 	pAC = pACList->pACnext;
759 	DestroyAccessList(pACList);
760 	pACList = pAC;
761     }
762     DestroyConsentUsers(&pADList);
763     DestroyConsentUsers(&pLUList);
764 
765     DestroyConfig(pConfig);
766     DestroyConfig(optConf);
767     DestroyConfig(config);
768 
769 #if HAVE_OPENSSL
770     if (ctx != (SSL_CTX *)0)
771 	SSL_CTX_free(ctx);
772     if (dh512 != (DH *)0)
773 	DH_free(dh512);
774     if (dh1024 != (DH *)0)
775 	DH_free(dh1024);
776     if (dh2048 != (DH *)0)
777 	DH_free(dh2048);
778     if (dh4096 != (DH *)0)
779 	DH_free(dh4096);
780 #endif
781 
782 #if USE_IPV6
783     /* clean up addrinfo stucts */
784     freeaddrinfo(bindAddr);
785     freeaddrinfo(bindBaseAddr);
786 #else
787     if (myAddrs != (struct in_addr *)0)
788 	free(myAddrs);
789 #endif
790 
791     DestroyBreakList();
792     DestroyTaskList();
793     DestroyStrings();
794     DestroyUserList();
795     if (substData != (SUBST *)0)
796 	free(substData);
797 }
798 
799 void
SummarizeDataStructures(void)800 SummarizeDataStructures(void)
801 {
802     GRPENT *pGE;
803     REMOTE *pRC;
804     ACCESS *pAC;
805     STRING *str;
806     CONSENT *pCE;
807     NAMES *usr;
808     int count;
809     long size;
810     long total = 0;
811     extern STRING *allStrings;
812 
813     if (!fDebug)
814 	return;
815 
816     for (size = 0, count = 0, pGE = pGroups; pGE != (GRPENT *)0;
817 	 pGE = pGE->pGEnext, count++) {
818 	size += sizeof(GRPENT);
819     }
820     CONDDEBUG((1, "Memory Usage (GRPENT objects): %ld (%d)", size, count));
821     total += size;
822 
823     for (size = 0, count = 0, pGE = pGroups; pGE != (GRPENT *)0;
824 	 pGE = pGE->pGEnext) {
825 	for (pCE = pGE->pCElist; pCE != (CONSENT *)0;
826 	     pCE = pCE->pCEnext, count++) {
827 	    size += strlen(pCE->server) + sizeof(CONSENT);
828 	    if (pCE->host != (char *)0)
829 		size += strlen(pCE->server);
830 	    if (pCE->device != (char *)0)
831 		size += strlen(pCE->device);
832 	    if (pCE->exec != (char *)0)
833 		size += strlen(pCE->exec);
834 	    if (pCE->master != (char *)0)
835 		size += strlen(pCE->master);
836 	    if (pCE->logfile != (char *)0)
837 		size += strlen(pCE->logfile);
838 	    if (pCE->initcmd != (char *)0)
839 		size += strlen(pCE->initcmd);
840 	    if (pCE->execSlave != (char *)0)
841 		size += strlen(pCE->execSlave);
842 	    if (pCE->motd != (char *)0)
843 		size += strlen(pCE->motd);
844 	    if (pCE->idlestring != (char *)0)
845 		size += strlen(pCE->idlestring);
846 	    if (pCE->replstring != (char *)0)
847 		size += strlen(pCE->replstring);
848 	    if (pCE->tasklist != (char *)0)
849 		size += strlen(pCE->tasklist);
850 	    if (pCE->breaklist != (char *)0)
851 		size += strlen(pCE->breaklist);
852 #if HAVE_FREEIPMI
853 	    if (pCE->username != (char *)0)
854 		size += strlen(pCE->username);
855 	    if (pCE->password != (char *)0)
856 		size += strlen(pCE->password);
857 #endif
858 	    if (pCE->fdlog != (CONSFILE *)0)
859 		size += sizeof(CONSFILE);
860 	    if (pCE->cofile != (CONSFILE *)0)
861 		size += sizeof(CONSFILE);
862 	    if (pCE->initfile != (CONSFILE *)0)
863 		size += sizeof(CONSFILE);
864 	    if (pCE->taskfile != (CONSFILE *)0)
865 		size += sizeof(CONSFILE);
866 	    if (pCE->aliases != (NAMES *)0) {
867 		NAMES *n;
868 		for (n = pCE->aliases; n != (NAMES *)0; n = n->next) {
869 		    size += sizeof(NAMES) + strlen(n->name);
870 		}
871 	    }
872 	    if (pCE->ro) {
873 		CONSENTUSERS *u;
874 		for (u = pCE->ro; u != (CONSENTUSERS *)0; u = u->next) {
875 		    size += sizeof(CONSENTUSERS) + strlen(u->user->name);
876 		}
877 	    }
878 	    if (pCE->rw) {
879 		CONSENTUSERS *u;
880 		for (u = pCE->rw; u != (CONSENTUSERS *)0; u = u->next) {
881 		    size += sizeof(CONSENTUSERS) + strlen(u->user->name);
882 		}
883 	    }
884 	}
885     }
886     CONDDEBUG((1, "Memory Usage (CONSENT objects): %ld (%d)", size,
887 	       count));
888     total += size;
889 
890     for (size = 0, count = 0, pRC = pRCList; pRC != (REMOTE *)0;
891 	 pRC = pRC->pRCnext, count++) {
892 	size += strlen(pRC->rserver) + strlen(pRC->rhost) + sizeof(REMOTE);
893 	if (pRC->aliases != (NAMES *)0) {
894 	    NAMES *n;
895 	    for (n = pRC->aliases; n != (NAMES *)0; n = n->next) {
896 		size += sizeof(NAMES) + strlen(n->name);
897 	    }
898 	}
899     }
900     CONDDEBUG((1, "Memory Usage (REMOTE objects): %ld (%d)", size, count));
901     total += size;
902 
903     for (size = 0, count = 0, pAC = pACList; pAC != (ACCESS *)0;
904 	 pAC = pAC->pACnext, count++) {
905 	size += strlen(pAC->pcwho) + sizeof(ACCESS);
906     }
907     CONDDEBUG((1, "Memory Usage (ACCESS objects): %ld (%d)", size, count));
908     total += size;
909 
910     for (size = 0, count = 0, str = allStrings; str != (STRING *)0;
911 	 str = str->next, count++) {
912 	size += str->allocated + sizeof(STRING);
913     }
914     CONDDEBUG((1, "Memory Usage (STRING objects): %ld (%d)", size, count));
915     total += size;
916 
917     for (size = 0, count = 0, usr = userList; usr != (NAMES *)0;
918 	 usr = usr->next, count++) {
919 	size += strlen(usr->name) + sizeof(NAMES);
920     }
921     CONDDEBUG((1, "Memory Usage (userList objects): %ld (%d)", size,
922 	       count));
923     total += size;
924 
925     CONDDEBUG((1, "Memory Usage (total): %ld", total));
926 }
927 
928 void
DumpDataStructures(void)929 DumpDataStructures(void)
930 {
931     GRPENT *pGE;
932     CONSENT *pCE;
933     REMOTE *pRC;
934     int i;
935     TASKS *t;
936 #if HAVE_FREEIPMI
937     static STRING *tmpString = (STRING *)0;
938     if (tmpString == (STRING *)0)
939 	tmpString = AllocString();
940 #endif
941 
942 #if HAVE_DMALLOC && DMALLOC_MARK_MAIN
943     CONDDEBUG((1, "DumpDataStructures(): dmalloc / MarkMain"));
944     dmalloc_log_changed(dmallocMarkMain, 1, 0, 1);
945 #endif
946 #define EMPTYSTR(x) x == (char *)0 ? "(null)" : x
947 #define FLAGSTR(x) x == FLAGTRUE ? "true" : (x == FLAGFALSE ? "false" : "unset")
948     if (!fDebug)
949 	return;
950 
951     SummarizeDataStructures();
952 
953     for (pGE = pGroups; pGE != (GRPENT *)0; pGE = pGE->pGEnext) {
954 	CONDDEBUG((1,
955 		   "DumpDataStructures(): group: id=%u port=%hu, pid=%lu, imembers=%d",
956 		   pGE->id, pGE->port, (unsigned long)pGE->pid,
957 		   pGE->imembers));
958 
959 	for (pCE = pGE->pCElist; pCE != (CONSENT *)0; pCE = pCE->pCEnext) {
960 	    switch (pCE->type) {
961 		case DEVICE:
962 		    CONDDEBUG((1,
963 			       "DumpDataStructures():  server=%s, type=DEVICE",
964 			       EMPTYSTR(pCE->server)));
965 		    CONDDEBUG((1,
966 			       "DumpDataStructures():  baud=%s, parity=%s, device=%s",
967 			       pCE->baud->acrate, pCE->parity->key,
968 			       EMPTYSTR(pCE->device)));
969 		    break;
970 		case EXEC:
971 		    CONDDEBUG((1,
972 			       "DumpDataStructures():  server=%s, type=EXEC",
973 			       EMPTYSTR(pCE->server)));
974 		    CONDDEBUG((1,
975 			       "DumpDataStructures():  execSlave=%s, exec=%s, ipid=%lu",
976 			       EMPTYSTR(pCE->execSlave),
977 			       EMPTYSTR(pCE->exec),
978 			       (unsigned long)pCE->ipid));
979 		    CONDDEBUG((1,
980 			       "DumpDataStructures():  execuid=%d, execgid=%d",
981 			       pCE->execuid, pCE->execgid));
982 
983 		    break;
984 #if HAVE_FREEIPMI
985 		case IPMI:
986 		    CONDDEBUG((1,
987 			       "DumpDataStructures():  server=%s, type=IPMI",
988 			       EMPTYSTR(pCE->server)));
989 		    CONDDEBUG((1,
990 			       "DumpDataStructures():  host=%s, username=%s, password=%s, ipmiprivlevel=%d",
991 			       EMPTYSTR(pCE->host),
992 			       EMPTYSTR(pCE->username),
993 			       EMPTYSTR(pCE->password),
994 			       pCE->ipmiprivlevel));
995 		    CONDDEBUG((1,
996 			       "DumpDataStructures():  ipmiwrkset=%d, ipmiworkaround=%u, ipmiciphersuite=%d",
997 			       pCE->ipmiwrkset, pCE->ipmiworkaround,
998 			       pCE->ipmiciphersuite));
999 		    FmtCtlStr(pCE->ipmikg->string, pCE->ipmikg->used - 1,
1000 			      tmpString);
1001 		    CONDDEBUG((1, "DumpDataStructures():  ipmikg=%s",
1002 			       EMPTYSTR(tmpString->string)));
1003 		    break;
1004 #endif
1005 		case HOST:
1006 		    CONDDEBUG((1,
1007 			       "DumpDataStructures():  server=%s, type=HOST",
1008 			       EMPTYSTR(pCE->server)));
1009 		    CONDDEBUG((1,
1010 			       "DumpDataStructures():  host=%s, raw=%s, netport=%hu, port=%hu, telnetState=%d",
1011 			       EMPTYSTR(pCE->host), FLAGSTR(pCE->raw),
1012 			       pCE->netport, pCE->port, pCE->telnetState));
1013 		    break;
1014 		case NOOP:
1015 		    CONDDEBUG((1,
1016 			       "DumpDataStructures():  server=%s, type=NOOP",
1017 			       EMPTYSTR(pCE->server)));
1018 		    break;
1019 		case UDS:
1020 		    CONDDEBUG((1,
1021 			       "DumpDataStructures():  server=%s, type=UDS",
1022 			       EMPTYSTR(pCE->server)));
1023 		    CONDDEBUG((1, "DumpDataStructures():  uds=%s",
1024 			       EMPTYSTR(pCE->uds)));
1025 		    break;
1026 		case UNKNOWNTYPE:
1027 		    CONDDEBUG((1,
1028 			       "DumpDataStructures():  server=%s, type=UNKNOWNTYPE",
1029 			       EMPTYSTR(pCE->server)));
1030 		    break;
1031 	    }
1032 	    if (pCE->aliases != (NAMES *)0) {
1033 		NAMES *n;
1034 		for (n = pCE->aliases; n != (NAMES *)0; n = n->next) {
1035 		    CONDDEBUG((1, "DumpDataStructures():  alias=%s",
1036 			       n->name));
1037 		}
1038 	    }
1039 	    CONDDEBUG((1,
1040 		       "DumpDataStructures():  fup=%d, fronly=%d, logfile=%s, breakNum=%d",
1041 		       pCE->fup, pCE->fronly, EMPTYSTR(pCE->logfile),
1042 		       pCE->breakNum));
1043 	    CONDDEBUG((1,
1044 		       "DumpDataStructures():  mark=%d, nextMark=%ld, autoReup=%hu, downHard=%s",
1045 		       pCE->mark, pCE->nextMark, pCE->autoReUp,
1046 		       FLAGSTR(pCE->downHard)));
1047 	    CONDDEBUG((1,
1048 		       "DumpDataStructures():  nolog=%d, cofile=%d, activitylog=%s, breaklog=%s",
1049 		       pCE->nolog, FileFDNum(pCE->cofile),
1050 		       FLAGSTR(pCE->activitylog), FLAGSTR(pCE->breaklog)));
1051 	    CONDDEBUG((1,
1052 		       "DumpDataStructures():  tasklog=%s, ixon=%s, ixany=%s, ixoff=%s",
1053 		       FLAGSTR(pCE->tasklog), FLAGSTR(pCE->ixon),
1054 		       FLAGSTR(pCE->ixany), FLAGSTR(pCE->ixoff)));
1055 	    CONDDEBUG((1,
1056 		       "DumpDataStructures():  autoreinit=%s, hupcl=%s, cstopb=%s, ondemand=%s",
1057 		       FLAGSTR(pCE->autoreinit), FLAGSTR(pCE->hupcl),
1058 		       FLAGSTR(pCE->cstopb), FLAGSTR(pCE->ondemand)));
1059 #if defined(CRTSCTS)
1060 	    CONDDEBUG((1, "DumpDataStructures():  crtscts=%s",
1061 		       FLAGSTR(pCE->crtscts)));
1062 #endif
1063 	    CONDDEBUG((1,
1064 		       "DumpDataStructures():  reinitoncc=%s, striphigh=%s",
1065 		       FLAGSTR(pCE->reinitoncc), FLAGSTR(pCE->striphigh)));
1066 	    CONDDEBUG((1, "DumpDataStructures():  unloved=%s, login=%s",
1067 		       FLAGSTR(pCE->unloved), FLAGSTR(pCE->login)));
1068 	    CONDDEBUG((1,
1069 		       "DumpDataStructures():  initpid=%lu, initcmd=%s, initfile=%d",
1070 		       (unsigned long)pCE->initpid, EMPTYSTR(pCE->initcmd),
1071 		       FileFDNum(pCE->initfile)));
1072 	    CONDDEBUG((1, "DumpDataStructures():  inituid=%d, initgid=%d",
1073 		       pCE->inituid, pCE->initgid));
1074 	    CONDDEBUG((1,
1075 		       "DumpDataStructures():  motd=%s, idletimeout=%d, idlestring=%s, replstring=%s",
1076 		       EMPTYSTR(pCE->motd), pCE->idletimeout,
1077 		       EMPTYSTR(pCE->idlestring),
1078 		       EMPTYSTR(pCE->replstring)));
1079 	    CONDDEBUG((1,
1080 		       "DumpDataStructures():  tasklist=%s, breaklist=%s, taskpid=%lu, taskfile=%d",
1081 		       EMPTYSTR(pCE->tasklist), EMPTYSTR(pCE->breaklist),
1082 		       (unsigned long)pCE->taskpid,
1083 		       FileFDNum(pCE->taskfile)));
1084 	    if (pCE->ro) {
1085 		CONSENTUSERS *u;
1086 		for (u = pCE->ro; u != (CONSENTUSERS *)0; u = u->next) {
1087 		    CONDDEBUG((1, "DumpDataStructures():  ro=%s%s",
1088 			       (u->not ? "!" : ""), u->user->name));
1089 		}
1090 	    }
1091 	    if (pCE->rw) {
1092 		CONSENTUSERS *u;
1093 		for (u = pCE->rw; u != (CONSENTUSERS *)0; u = u->next) {
1094 		    CONDDEBUG((1, "DumpDataStructures():  rw=%s%s",
1095 			       (u->not ? "!" : ""), u->user->name));
1096 		}
1097 	    }
1098 	    CONDDEBUG((1, "DumpDataStructures():  ------"));
1099 	}
1100     }
1101     for (pRC = pRCList; (REMOTE *)0 != pRC; pRC = pRC->pRCnext) {
1102 	CONDDEBUG((1, "DumpDataStructures(): remote: rserver=%s, rhost=%s",
1103 		   EMPTYSTR(pRC->rserver), EMPTYSTR(pRC->rhost)));
1104 	if (pRC->aliases != (NAMES *)0) {
1105 	    NAMES *n;
1106 	    for (n = pRC->aliases; n != (NAMES *)0; n = n->next) {
1107 		CONDDEBUG((1, "DumpDataStructures():  alias=%s", n->name));
1108 	    }
1109 	}
1110     }
1111     for (i = 0; i < BREAKLISTSIZE; i++) {
1112 	CONDDEBUG((1,
1113 		   "DumpDataStructures(): break: #%c, string=%s, delay=%d, confirm=%s",
1114 		   '1' + i + (i > 8 ? BREAKALPHAOFFSET : 0),
1115 		   EMPTYSTR(breakList[i].seq->string), breakList[i].delay,
1116 		   FLAGSTR(breakList[i].confirm)));
1117     }
1118     for (t = taskList; t != (TASKS *)0; t = t->next) {
1119 	CONDDEBUG((1,
1120 		   "DumpDataStructures(): task: id=%c, cmd=%s, descr=%s, uid=%d, gid=%d, subst=%s, confirm=%s",
1121 		   t->id, EMPTYSTR(t->cmd->string),
1122 		   EMPTYSTR(t->descr->string), t->uid, t->gid,
1123 		   EMPTYSTR(t->subst), FLAGSTR(t->confirm)));
1124     }
1125 }
1126 
1127 /* This makes sure a directory exists and tries to create it if it
1128  * doesn't.  returns 0 for success, -1 for error
1129  */
1130 #if USE_UNIX_DOMAIN_SOCKETS
1131 int
VerifyEmptyDirectory(char * d)1132 VerifyEmptyDirectory(char *d)
1133 {
1134     struct stat dstat;
1135     DIR *dir;
1136     struct dirent *de;
1137 # if 0				/* See below */
1138     STRING *path = (STRING *)0;
1139 # endif
1140     int retval = 0;
1141 
1142     while (1) {
1143 	if (stat(d, &dstat) == -1) {
1144 	    if (errno == ENOENT) {
1145 		if (mkdir(d, 0755) == -1) {
1146 		    Error("mkdir(%s): %s", d, strerror(errno));
1147 		    return -1;
1148 		}
1149 		CONDDEBUG((1, "VerifyEmptyDirectory: created `%s'", d));
1150 		continue;
1151 	    } else {
1152 		Error("stat(%s): %s", d, strerror(errno));
1153 		return -1;
1154 	    }
1155 	}
1156 	if (S_ISDIR(dstat.st_mode))
1157 	    break;
1158 	return -1;
1159     }
1160 
1161     /* now make sure it's empty...erase anything you see, etc */
1162     if ((dir = opendir(d)) == (DIR *) 0) {
1163 	Error("opendir(%s): %s", d, strerror(errno));
1164 	return -1;
1165     }
1166 
1167     while ((de = readdir(dir)) != (struct dirent *)0) {
1168 	if ((strcmp(de->d_name, ".") == 0) ||
1169 	    (strcmp(de->d_name, "..") == 0))
1170 	    continue;
1171 /* we're going to just let the user deal with non-empty directories */
1172 	Error("non-empty directory `%s'", d);
1173 	retval = -1;
1174 	break;
1175 /* this is probably too extreme.  if someone happens to point conserver
1176  * at /etc, for example, it could (if running as root) nuke the password
1177  * database, config files, etc.  too many important files could be
1178  * shredded with a small typo.
1179  */
1180 # if 0
1181 	if (path == (STRING *)0)
1182 	    path = AllocString();
1183 	BuildStringPrint(path, "%s/%s", d, de->d_name);
1184 	if (stat(path->string, &dstat) == -1) {
1185 	    Error("stat(%s): %s", path->string, strerror(errno));
1186 	    retval = -1;
1187 	    break;
1188 	}
1189 	if (S_ISDIR(dstat.st_mode)) {
1190 	    if (rmdir(path->string) != 0) {
1191 		Error("rmdir(%s): %s", path->string, strerror(errno));
1192 		retval = -1;
1193 		break;
1194 	    }
1195 	} else {
1196 	    if (unlink(path->string) != 0) {
1197 		Error("unlink(%s): %s", path->string, strerror(errno));
1198 		retval = -1;
1199 		break;
1200 	    }
1201 	}
1202 # endif
1203     }
1204 
1205 # if 0				/* See above */
1206     if (path != (STRING *)0)
1207 	DestroyString(path);
1208 # endif
1209 
1210     /* free dir data structure */
1211     closedir(dir);
1212 
1213     return retval;
1214 }
1215 #endif
1216 
1217 /* find out where/who we are						(ksb)
1218  * parse optons
1219  * read in the config file, open the log file
1220  * spawn the kids to drive the console groups
1221  * become the master server
1222  * shutdown with grace
1223  * exit happy
1224  */
1225 int
main(int argc,char ** argv)1226 main(int argc, char **argv)
1227 {
1228     int i;
1229     FILE *fpConfig = (FILE *)0;
1230     static char acOpts[] = "7a:b:c:C:dDEFhiL:m:M:noO:p:P:RSuU:Vv";
1231     extern int optopt;
1232     extern char *optarg;
1233     struct passwd *pwd;
1234     char *origuser = (char *)0;
1235     char *curuser = (char *)0;
1236     int curuid = 0;
1237     GRPENT *pGE = (GRPENT *)0;
1238 #if !USE_UNIX_DOMAIN_SOCKETS
1239 # if USE_IPV6
1240     int s;
1241     struct addrinfo hints;
1242 # else
1243 #  if HAVE_INET_ATON
1244     struct in_addr inetaddr;
1245 #  endif
1246 # endif
1247 #endif
1248 
1249     isMultiProc = 1;		/* make sure stuff has the pid */
1250 
1251     thepid = getpid();
1252     if ((char *)0 == (progname = strrchr(argv[0], '/'))) {
1253 	progname = argv[0];
1254     } else {
1255 	++progname;
1256     }
1257 
1258     setpwent();
1259 
1260     /* if we read from stdin (by accident) we don't wanna block.
1261      * we just don't want any more input at this point.
1262      */
1263     close(0);
1264     if (0 != open("/dev/null", O_RDWR, 0644)) {
1265 	Error("open(/dev/null): %s", strerror(errno));
1266 	Bye(EX_OSFILE);
1267     }
1268 #if HAVE_SETLINEBUF
1269     setlinebuf(stdout);
1270     setlinebuf(stderr);
1271 #endif
1272 #if HAVE_SETVBUF
1273     setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
1274     setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
1275 #endif
1276 
1277     /* Initialize the break list */
1278     InitBreakList();
1279 
1280     /* prep the config options */
1281     if ((optConf = (CONFIG *)calloc(1, sizeof(CONFIG)))
1282 	== (CONFIG *)0)
1283 	OutOfMem();
1284     if ((config = (CONFIG *)calloc(1, sizeof(CONFIG)))
1285 	== (CONFIG *)0)
1286 	OutOfMem();
1287 
1288     while (EOF != (i = getopt(argc, argv, acOpts))) {
1289 	switch (i) {
1290 	    case '7':
1291 		fStrip = 1;
1292 		break;
1293 	    case 'a':
1294 		optConf->defaultaccess = *optarg;
1295 		if (isupper((int)(optConf->defaultaccess)))
1296 		    optConf->defaultaccess =
1297 			tolower(optConf->defaultaccess);
1298 		switch (optConf->defaultaccess) {
1299 		    case 'r':
1300 		    case 'a':
1301 		    case 't':
1302 			break;
1303 		    default:
1304 			Error("unknown access type `%s'", optarg);
1305 			Bye(EX_USAGE);
1306 		}
1307 		break;
1308 	    case 'b':
1309 		if ((optConf->secondaryport = StrDup(optarg)) == (char *)0)
1310 		    OutOfMem();
1311 		break;
1312 	    case 'c':
1313 #if HAVE_OPENSSL
1314 		if ((optConf->sslcredentials =
1315 		     StrDup(optarg)) == (char *)0)
1316 		    OutOfMem();
1317 #endif
1318 		break;
1319 	    case 'C':
1320 		pcConfig = optarg;
1321 		break;
1322 	    case 'd':
1323 		optConf->daemonmode = FLAGTRUE;
1324 		break;
1325 	    case 'D':
1326 		fDebug++;
1327 		break;
1328 	    case 'E':
1329 #if HAVE_OPENSSL
1330 		optConf->sslrequired = FLAGFALSE;
1331 #endif
1332 		break;
1333 	    case 'F':
1334 		fNoautoreup = 1;
1335 		break;
1336 	    case 'h':
1337 		Usage(1);
1338 		Bye(EX_OK);
1339 	    case 'i':
1340 		fNoinit = 1;
1341 		break;
1342 	    case 'L':
1343 		if ((optConf->logfile = StrDup(optarg)) == (char *)0)
1344 		    OutOfMem();
1345 		break;
1346 	    case 'm':
1347 		cMaxMemb = atoi(optarg);
1348 		if (cMaxMemb <= 0) {
1349 		    Error("ignoring invalid -m option (%d <= 0)",
1350 			  cMaxMemb);
1351 		    cMaxMemb = MAXMEMB;
1352 		}
1353 		break;
1354 	    case 'M':
1355 		interface = StrDup(optarg);
1356 		break;
1357 	    case 'n':
1358 		/* noop now */
1359 		break;
1360 	    case 'o':
1361 		/* try reopening downed consoles on connect */
1362 		fReopen = 1;
1363 		break;
1364 	    case 'O':
1365 		/* How often to try opening all down consoles, in minutes */
1366 		optConf->reinitcheck = atoi(optarg);
1367 		break;
1368 	    case 'p':
1369 		if ((optConf->primaryport = StrDup(optarg)) == (char *)0)
1370 		    OutOfMem();
1371 		break;
1372 	    case 'P':
1373 		if ((optConf->passwdfile = StrDup(optarg)) == (char *)0)
1374 		    OutOfMem();
1375 		break;
1376 	    case 'R':
1377 		optConf->redirect = FLAGFALSE;
1378 		break;
1379 	    case 'S':
1380 		fSyntaxOnly++;
1381 		break;
1382 	    case 'u':
1383 		fAll = 1;
1384 		break;
1385 	    case 'U':
1386 		if ((optConf->unifiedlog = StrDup(optarg)) == (char *)0)
1387 		    OutOfMem();
1388 		break;
1389 	    case 'V':
1390 		fVersion = 1;
1391 		break;
1392 	    case 'v':
1393 		fVerbose = 1;
1394 		break;
1395 	    case '\?':
1396 		Usage(0);
1397 		Bye(EX_USAGE);
1398 	    default:
1399 		Error("option %c needs a parameter", optopt);
1400 		Bye(EX_USAGE);
1401 	}
1402     }
1403 
1404     if (fVersion) {
1405 	Version();
1406 	Bye(EX_OK);
1407     }
1408 
1409     Msg(MyVersion());
1410 
1411 #if HAVE_GETLOGIN
1412     origuser = getlogin();
1413 #endif
1414     curuid = getuid();
1415 
1416     if ((struct passwd *)0 != (pwd = getpwuid(curuid)))
1417 	curuser = pwd->pw_name;
1418 
1419     /* chuck any empty username */
1420     if (curuser != (char *)0 && curuser[0] == '\000')
1421 	curuser = (char *)0;
1422 
1423     if (startedMsg == (STRING *)0)
1424 	startedMsg = AllocString();
1425     if (curuser == (char *)0)
1426 	if (origuser == (char *)0)
1427 	    BuildStringPrint(startedMsg, "started as uid %d by uid %d",
1428 			     curuid, curuid);
1429 	else
1430 	    BuildStringPrint(startedMsg, "started as uid %d by `%s'",
1431 			     curuid, origuser);
1432     else
1433 	BuildStringPrint(startedMsg, "started as `%s' by `%s'", curuser,
1434 			 (origuser == (char *)0) ? curuser : origuser);
1435     endpwent();
1436     Msg("%s", startedMsg->string);
1437 
1438 #if HAVE_GETSPNAM && !HAVE_PAM
1439     if (!fSyntaxOnly && (geteuid() != 0)) {
1440 	Msg("warning: running as a non-root user - any shadow password usage will most likely fail!");
1441     }
1442 #endif
1443 
1444     if (fSyntaxOnly)
1445 	Msg("performing configuration file syntax check");
1446 
1447     /* must do all this so IsMe() works right */
1448     if (gethostname(myHostname, MAXHOSTNAME) != 0) {
1449 	Error("gethostname(): %s", strerror(errno));
1450 	Bye(EX_OSERR);
1451     }
1452 #if !USE_IPV6
1453     ProbeInterfaces(bindAddr);
1454 #endif
1455 
1456     /* initialize the timers */
1457     for (i = 0; i < T_MAX; i++)
1458 	timers[i] = (time_t)0;
1459 
1460     /* read the config file */
1461     if ((FILE *)0 == (fpConfig = fopen(pcConfig, "r"))) {
1462 	Error("fopen(%s): %s", pcConfig, strerror(errno));
1463 	Bye(EX_NOINPUT);
1464     }
1465     ReadCfg(pcConfig, fpConfig);
1466     fclose(fpConfig);
1467 
1468 #if !USE_UNIX_DOMAIN_SOCKETS
1469     /* set up the port to bind to */
1470     if (optConf->primaryport != (char *)0)
1471 	config->primaryport = StrDup(optConf->primaryport);
1472     else if (pConfig->primaryport != (char *)0)
1473 	config->primaryport = StrDup(pConfig->primaryport);
1474     else
1475 	config->primaryport = StrDup(defConfig.primaryport);
1476     if (config->primaryport == (char *)0)
1477 	OutOfMem();
1478 
1479 # if !USE_IPV6
1480     /* Look for non-numeric characters */
1481     for (i = 0; config->primaryport[i] != '\000'; i++)
1482 	if (!isdigit((int)config->primaryport[i]))
1483 	    break;
1484 
1485     if (config->primaryport[i] == '\000') {
1486 	/* numeric only */
1487 	bindPort = atoi(config->primaryport);
1488     } else {
1489 	/* non-numeric only */
1490 	struct servent *pSE;
1491 	if ((struct servent *)0 ==
1492 	    (pSE = getservbyname(config->primaryport, "tcp"))) {
1493 	    Error("getservbyname(%s) failed", config->primaryport);
1494 	    Bye(EX_OSERR);
1495 	} else {
1496 	    bindPort = ntohs((unsigned short)pSE->s_port);
1497 	}
1498     }
1499 # endif
1500 
1501     /* set up the secondary port to bind to */
1502     if (optConf->secondaryport != (char *)0)
1503 	config->secondaryport = StrDup(optConf->secondaryport);
1504     else if (pConfig->secondaryport != (char *)0)
1505 	config->secondaryport = StrDup(pConfig->secondaryport);
1506     else
1507 	config->secondaryport = StrDup(defConfig.secondaryport);
1508     if (config->secondaryport == (char *)0)
1509 	OutOfMem();
1510 
1511 # if !USE_IPV6
1512     /* Look for non-numeric characters */
1513     for (i = 0; config->secondaryport[i] != '\000'; i++)
1514 	if (!isdigit((int)config->secondaryport[i]))
1515 	    break;
1516 
1517     if (config->secondaryport[i] == '\000') {
1518 	/* numeric only */
1519 	bindBasePort = atoi(config->secondaryport);
1520     } else {
1521 	/* non-numeric only */
1522 	struct servent *pSE;
1523 	if ((struct servent *)0 ==
1524 	    (pSE = getservbyname(config->secondaryport, "tcp"))) {
1525 	    Error("getservbyname(%s) failed", config->secondaryport);
1526 	    Bye(EX_OSERR);
1527 	} else {
1528 	    bindBasePort = ntohs((unsigned short)pSE->s_port);
1529 	}
1530     }
1531 # endif
1532 #endif
1533 
1534 #if USE_IPV6
1535     /* set up the address to bind to */
1536     memset(&hints, 0, sizeof(hints));
1537     hints.ai_family = AF_UNSPEC;
1538     hints.ai_socktype = SOCK_STREAM;
1539     hints.ai_flags |= AI_PASSIVE;
1540 
1541     /* create list or IPs suitable for primaryport */
1542     s = getaddrinfo(interface, config->primaryport, &hints, &bindAddr);
1543     if (s) {
1544 	Error("getaddrinfo(%s): %s", interface, gai_strerror(s));
1545 	Bye(EX_OSERR);
1546     }
1547 
1548     /* create list or IPs suitable for secondaryport */
1549     s = getaddrinfo(interface, config->secondaryport, &hints,
1550 		    &bindBaseAddr);
1551     if (s) {
1552 	Error("getaddrinfo(%s): %s", interface, gai_strerror(s));
1553 	Bye(EX_OSERR);
1554     }
1555 #elif USE_UNIX_DOMAIN_SOCKETS
1556     /* Don't do any redirects if we're purely local
1557      * (but it allows them to see where remote consoles are)
1558      */
1559     optConf->redirect = FLAGFALSE;
1560     if (interface == (char *)0)
1561 	interface = UDSDIR;
1562 #else
1563     /* set up the address to bind to */
1564     if (interface == (char *)0 ||
1565 	(interface[0] == '*' && interface[1] == '\000'))
1566 	bindAddr = INADDR_ANY;
1567     else {
1568 # if HAVE_INET_ATON
1569 	if (inet_aton(interface, &inetaddr) == 0) {
1570 	    Error("inet_aton(%s): %s", interface, "invalid IP address");
1571 	    Bye(EX_OSERR);
1572 	}
1573 	bindAddr = inetaddr.s_addr;
1574 # else
1575 	bindAddr = inet_addr(interface);
1576 	if (bindAddr == (in_addr_t) (-1)) {
1577 	    Error("inet_addr(%s): %s", interface, "invalid IP address");
1578 	    Bye(EX_OSERR);
1579 	}
1580 # endif
1581     }
1582     if (fDebug) {
1583 	struct in_addr ba;
1584 	ba.s_addr = bindAddr;
1585 	CONDDEBUG((1, "main(): bind address set to `%s'", inet_ntoa(ba)));
1586     }
1587 #endif
1588 
1589     if (optConf->passwdfile != (char *)0)
1590 	config->passwdfile = StrDup(optConf->passwdfile);
1591     else if (pConfig->passwdfile != (char *)0)
1592 	config->passwdfile = StrDup(pConfig->passwdfile);
1593     else
1594 	config->passwdfile = StrDup(defConfig.passwdfile);
1595     if (config->passwdfile == (char *)0)
1596 	OutOfMem();
1597 
1598     if (optConf->logfile != (char *)0)
1599 	config->logfile = StrDup(optConf->logfile);
1600     else if (pConfig->logfile != (char *)0)
1601 	config->logfile = StrDup(pConfig->logfile);
1602     else
1603 	config->logfile = StrDup(defConfig.logfile);
1604     if (config->logfile == (char *)0)
1605 	OutOfMem();
1606 
1607     if (optConf->reinitcheck != 0)
1608 	config->reinitcheck = optConf->reinitcheck;
1609     else if (pConfig->reinitcheck != 0)
1610 	config->reinitcheck = pConfig->reinitcheck;
1611     else
1612 	config->reinitcheck = defConfig.reinitcheck;
1613 
1614     if (optConf->defaultaccess != '\000')
1615 	config->defaultaccess = optConf->defaultaccess;
1616     else if (pConfig->defaultaccess != '\000')
1617 	config->defaultaccess = pConfig->defaultaccess;
1618     else
1619 	config->defaultaccess = defConfig.defaultaccess;
1620 
1621     if (optConf->daemonmode != FLAGUNKNOWN)
1622 	config->daemonmode = optConf->daemonmode;
1623     else if (pConfig->daemonmode != FLAGUNKNOWN)
1624 	config->daemonmode = pConfig->daemonmode;
1625     else
1626 	config->daemonmode = defConfig.daemonmode;
1627 
1628     if (optConf->redirect != FLAGUNKNOWN)
1629 	config->redirect = optConf->redirect;
1630     else if (pConfig->redirect != FLAGUNKNOWN)
1631 	config->redirect = pConfig->redirect;
1632     else
1633 	config->redirect = defConfig.redirect;
1634 
1635     if (optConf->autocomplete != FLAGUNKNOWN)
1636 	config->autocomplete = optConf->autocomplete;
1637     else if (pConfig->autocomplete != FLAGUNKNOWN)
1638 	config->autocomplete = pConfig->autocomplete;
1639     else
1640 	config->autocomplete = defConfig.autocomplete;
1641 
1642     if (optConf->loghostnames != FLAGUNKNOWN)
1643 	config->loghostnames = optConf->loghostnames;
1644     else if (pConfig->loghostnames != FLAGUNKNOWN)
1645 	config->loghostnames = pConfig->loghostnames;
1646     else
1647 	config->loghostnames = defConfig.loghostnames;
1648 
1649     if (optConf->unifiedlog != (char *)0) {
1650 	config->unifiedlog = StrDup(optConf->unifiedlog);
1651 	if (config->unifiedlog == (char *)0)
1652 	    OutOfMem();
1653     } else if (pConfig->unifiedlog != (char *)0) {
1654 	config->unifiedlog = StrDup(pConfig->unifiedlog);
1655 	if (config->unifiedlog == (char *)0)
1656 	    OutOfMem();
1657     } else if (defConfig.unifiedlog != (char *)0) {
1658 	config->unifiedlog = StrDup(defConfig.unifiedlog);
1659 	if (config->unifiedlog == (char *)0)
1660 	    OutOfMem();
1661     }
1662 
1663     if (optConf->initdelay != 0)
1664 	config->initdelay = optConf->initdelay;
1665     else if (pConfig->initdelay != 0)
1666 	config->initdelay = pConfig->initdelay;
1667     else
1668 	config->initdelay = defConfig.initdelay;
1669 
1670 #if HAVE_OPENSSL
1671     if (optConf->sslrequired != FLAGUNKNOWN)
1672 	config->sslrequired = optConf->sslrequired;
1673     else if (pConfig->sslrequired != FLAGUNKNOWN)
1674 	config->sslrequired = pConfig->sslrequired;
1675     else
1676 	config->sslrequired = defConfig.sslrequired;
1677 
1678     if (optConf->sslreqclientcert != FLAGUNKNOWN)
1679 	config->sslreqclientcert = optConf->sslreqclientcert;
1680     else if (pConfig->sslreqclientcert != FLAGUNKNOWN)
1681 	config->sslreqclientcert = pConfig->sslreqclientcert;
1682     else
1683 	config->sslreqclientcert = defConfig.sslreqclientcert;
1684 
1685     if (optConf->sslcredentials != (char *)0)
1686 	config->sslcredentials = StrDup(optConf->sslcredentials);
1687     else if (pConfig->sslcredentials != (char *)0)
1688 	config->sslcredentials = StrDup(pConfig->sslcredentials);
1689     else
1690 	config->sslcredentials = StrDup(defConfig.sslcredentials);
1691 
1692     if (optConf->sslcacertificatefile != (char *)0)
1693 	config->sslcacertificatefile =
1694 	    StrDup(optConf->sslcacertificatefile);
1695     else if (pConfig->sslcacertificatefile != (char *)0)
1696 	config->sslcacertificatefile =
1697 	    StrDup(pConfig->sslcacertificatefile);
1698     else
1699 	config->sslcacertificatefile =
1700 	    StrDup(defConfig.sslcacertificatefile);
1701 #endif
1702 
1703 #if HAVE_SETPROCTITLE
1704     if (optConf->setproctitle != FLAGUNKNOWN)
1705 	config->setproctitle = optConf->setproctitle;
1706     else if (pConfig->setproctitle != FLAGUNKNOWN)
1707 	config->setproctitle = pConfig->setproctitle;
1708     else
1709 	config->setproctitle = defConfig.setproctitle;
1710 #endif
1711 
1712 #if HAVE_DMALLOC && DMALLOC_MARK_MAIN
1713     dmallocMarkMain = dmalloc_mark();
1714 #endif
1715 
1716     if (pGroups == (GRPENT *)0 && pRCList == (REMOTE *)0) {
1717 	Error("no consoles found in configuration file");
1718     } else if (fSyntaxOnly) {
1719 	/* short-circuit */
1720 #if USE_UNIX_DOMAIN_SOCKETS
1721     } else if (VerifyEmptyDirectory(interface) == -1) {
1722 	Error("Master(): %s: unusable socket directory", interface);
1723 #endif
1724     } else {
1725 #if HAVE_OPENSSL
1726 	/* Prep the SSL layer */
1727 	SetupSSL();
1728 #endif
1729 #if HAVE_GSSAPI
1730 	SetupGSSAPI();
1731 #endif
1732 
1733 	if (config->daemonmode == FLAGTRUE)
1734 	    Daemonize();
1735 
1736 	ReopenUnifiedlog();
1737 
1738 	/* if no one can use us we need to come up with a default
1739 	 */
1740 	if (pACList == (ACCESS *)0)
1741 #if USE_IPV6
1742 	    SetDefAccess();
1743 #else
1744 	    SetDefAccess(myAddrs, myHostname);
1745 #endif
1746 
1747 	/* spawn all the children, so fix kids has an initial pid
1748 	 */
1749 	for (pGE = pGroups; pGE != (GRPENT *)0; pGE = pGE->pGEnext) {
1750 	    if (pGE->imembers == 0)
1751 		continue;
1752 
1753 	    Spawn(pGE, -1);
1754 	    Verbose("group #%d pid %lu on port %hu", pGE->id,
1755 		    (unsigned long)pGE->pid, pGE->port);
1756 	}
1757 
1758 #if HAVE_SETPROCTITLE
1759 	if (config->setproctitle == FLAGTRUE) {
1760 	    REMOTE *pRC;
1761 	    GRPENT *pGE;
1762 	    int local = 0, remote = 0;
1763 	    for (pGE = pGroups; pGE != (GRPENT *)0; pGE = pGE->pGEnext)
1764 		local += pGE->imembers;
1765 	    for (pRC = pRCList; (REMOTE *)0 != pRC; pRC = pRC->pRCnext)
1766 		remote++;
1767 	    setproctitle("master: port %hu, %d local, %d remote",
1768 # if USE_IPV6
1769 			 config->primaryport,
1770 # elif USE_UNIX_DOMAIN_SOCKETS
1771 			 0,
1772 # else
1773 			 bindPort,
1774 # endif
1775 			 local, remote);
1776 	}
1777 #endif
1778 
1779 	if (fVerbose) {
1780 	    ACCESS *pACtmp;
1781 	    for (pACtmp = pACList; pACtmp != (ACCESS *)0;
1782 		 pACtmp = pACtmp->pACnext) {
1783 		Verbose("access type `%c' for `%s'", pACtmp->ctrust,
1784 			pACtmp->pcwho);
1785 	    }
1786 	}
1787 
1788 	pRCUniq = FindUniq(pRCList);
1789 
1790 	/* output unique console server peers?
1791 	 */
1792 	if (fVerbose) {
1793 	    REMOTE *pRC;
1794 	    for (pRC = pRCUniq; (REMOTE *)0 != pRC; pRC = pRC->pRCuniq) {
1795 		Verbose("peer server on `%s'", pRC->rhost);
1796 	    }
1797 	}
1798 
1799 	fflush(stdout);
1800 	fflush(stderr);
1801 	Master();
1802 
1803 	/* stop putting kids back, and shoot them
1804 	 */
1805 	SimpleSignal(SIGCHLD, SIG_DFL);
1806 	SignalKids(SIGTERM);
1807     }
1808 
1809     if (unifiedlog != (CONSFILE *)0)
1810 	FileClose(&unifiedlog);
1811 
1812     DumpDataStructures();
1813 
1814     Msg("terminated");
1815     endpwent();
1816     if (fSyntaxOnly && fErrorPrinted)
1817 	Bye(EX_DATAERR);
1818     else
1819 	Bye(EX_OK);
1820     return EX_OK;		/* never gets here clears the compiler warning */
1821 }
1822