1 /*
2  * Copyright (c) 1998,2001
3  *	Traakan, Inc., Los Altos, CA
4  *	All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice unmodified, this list of conditions, and the following
11  *    disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 /*
30  * Project:  NDMJOB
31  * Ident:    $Id: $
32  *
33  * Description:
34  *	This contains code fragments common between the
35  *	O/S (Operating System) portions of NDMJOBLIB.
36  *
37  *	This file is #include'd by the O/S specific ndmos_*.c
38  *	file, and fragments are selected by #ifdef's.
39  *
40  *	There are four major portions:
41  *	1) Misc support routines: password check, local info, etc
42  *	2) Non-blocking I/O support routines
43  *	3) Tape interfacs ndmos_tape_xxx()
44  *	4) OS Specific NDMP request dispatcher which intercepts
45  *	   requests implemented here, such as SCSI operations
46  *	   and system configuration queries.
47  */
48 
49 
50 
51 
52 /*
53  * CONFIG SUPPORT
54  ****************************************************************
55  */
56 
57 #ifdef NDMOS_COMMON_SYNC_CONFIG_INFO
58 /*
59  * Get local info. Supports NDMPx_CONFIG_GET_HOST_INFO,
60  * NDMP3_CONFIG_GET_SERVER_INFO, and NDMPx_CONFIG_GET_SCSI_INFO.
61  */
62 void
ndmos_sync_config_info(struct ndm_session * sess)63 ndmos_sync_config_info (struct ndm_session *sess)
64 {
65 	static struct utsname	unam;
66 	static char		osbuf[100];
67 	static char		idbuf[30];
68 	static char		revbuf[50];
69 	char			obuf[5];
70 
71 	if (sess->config_info.hostname) {
72 		/* already set */
73 		return;
74 	}
75 
76 	obuf[0] = (char)(NDMOS_ID >> 24);
77 	obuf[1] = (char)(NDMOS_ID >> 16);
78 	obuf[2] = (char)(NDMOS_ID >> 8);
79 	obuf[3] = (char)(NDMOS_ID >> 0);
80 	obuf[4] = 0;
81 
82 	uname (&unam);
83 	sprintf (idbuf, "%lu", gethostid());
84 	/*
85 	 * give CONTROL via NDMPv2 a chance to recognize this
86 	 * implementation (no ndmp2_config_get_server).
87 	 */
88 	sprintf (osbuf, "%s (running %s from %s)",
89 			unam.sysname,
90 			NDMOS_CONST_PRODUCT_NAME,
91 			NDMOS_CONST_VENDOR_NAME);
92 
93 	sess->config_info.hostname = unam.nodename;
94 	sess->config_info.os_type = osbuf;
95 	sess->config_info.os_vers = unam.release;
96 	sess->config_info.hostid = idbuf;
97 
98 	sess->config_info.vendor_name = NDMOS_CONST_VENDOR_NAME;
99 	sess->config_info.product_name = NDMOS_CONST_PRODUCT_NAME;
100 
101 	sprintf (revbuf, "%s LIB:%d.%d/%s OS:%s (%s)",
102 		NDMOS_CONST_PRODUCT_REVISION,
103 		NDMJOBLIB_VERSION, NDMJOBLIB_RELEASE,
104 		NDMOS_CONST_NDMJOBLIB_REVISION,
105 		NDMOS_CONST_NDMOS_REVISION,
106 		obuf);
107 
108 	sess->config_info.revision_number = revbuf;
109 
110 	/* best effort; note that this loads scsi and tape config */
111 	ndmcfg_load (sess->param.config_file_name, &sess->config_info);
112 }
113 #endif /* NDMOS_COMMON_SYNC_CONFIG_INFO */
114 
115 
116 
117 
118 /*
119  * AUTHENTICATION SUPPORT
120  ****************************************************************
121  */
122 
123 #ifdef NDMOS_COMMON_OK_NAME_PASSWORD
124 /*
125  * Determine whether the clear-text account name and password
126  * are valid. Supports NDMPx_CONNECT_CLIENT_AUTH requests.
127  */
128 int
ndmos_ok_name_password(struct ndm_session * sess,char * name,char * pass)129 ndmos_ok_name_password (struct ndm_session *sess, char *name, char *pass)
130 {
131 	if (strcmp (name, "ndmp") != 0)
132 		return 0;
133 
134 	if (strcmp (pass, "ndmp") != 0)
135 		return 0;
136 
137 	return 1;	/* OK */
138 }
139 #endif /* NDMOS_COMMON_OK_NAME_PASSWORD */
140 
141 
142 
143 
144 #ifdef NDMOS_COMMON_MD5
145 /*
146  * MD5 authentication support
147  *
148  * See ndml_md5.c
149  */
150 
151 int
ndmos_get_md5_challenge(struct ndm_session * sess)152 ndmos_get_md5_challenge (struct ndm_session *sess)
153 {
154 	ndmmd5_generate_challenge (sess->md5_challenge);
155 	sess->md5_challenge_valid = 1;
156 	return 0;
157 }
158 
159 int
ndmos_ok_name_md5_digest(struct ndm_session * sess,char * name,char digest[16])160 ndmos_ok_name_md5_digest (struct ndm_session *sess,
161   char *name, char digest[16])
162 {
163 	if (strcmp (name, "ndmp") != 0)
164 		return 0;
165 
166 	if (!ndmmd5_ok_digest (sess->md5_challenge, "ndmp", digest))
167 		return 0;
168 
169 	return 1;	/* OK */
170 }
171 #endif /* NDMOS_COMMON_MD5 */
172 
173 
174 
175 #ifdef NDMOS_COMMON_NONBLOCKING_IO_SUPPORT
176 /*
177  * NON-BLOCKING I/O SUPPORT
178  ****************************************************************
179  * As support non-blocking I/O for NDMCHAN, condition different
180  * types of file descriptors to not block.
181  */
182 
183 void
ndmos_condition_listen_socket(struct ndm_session * sess,int sock)184 ndmos_condition_listen_socket (struct ndm_session *sess, int sock)
185 {
186 	int		flag;
187 
188 	flag = 1;
189 	setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (void*)&flag, sizeof flag);
190 }
191 
192 void
ndmos_condition_control_socket(struct ndm_session * sess,int sock)193 ndmos_condition_control_socket (struct ndm_session *sess, int sock)
194 {
195 	/* nothing */
196 }
197 
198 void
ndmos_condition_image_stream_socket(struct ndm_session * sess,int sock)199 ndmos_condition_image_stream_socket (struct ndm_session *sess, int sock)
200 {
201 	fcntl (sock, F_SETFL, O_NONBLOCK);
202 	signal (SIGPIPE, SIG_IGN);
203 }
204 
205 void
ndmos_condition_pipe_fd(struct ndm_session * sess,int fd)206 ndmos_condition_pipe_fd (struct ndm_session *sess, int fd)
207 {
208 	fcntl (fd, F_SETFL, O_NONBLOCK);
209 	signal (SIGPIPE, SIG_IGN);
210 }
211 #endif /* NDMOS_COMMON_NONBLOCKING_IO_SUPPORT */
212 
213 
214 
215 
216 #ifdef NDMOS_COMMON_TAPE_INTERFACE
217 #ifndef NDMOS_OPTION_NO_TAPE_AGENT
218 #ifndef NDMOS_OPTION_TAPE_SIMULATOR
219 /*
220  * TAPE INTERFACE
221  ****************************************************************
222  * These interface to the O/S specific tape drivers and subsystem.
223  * They must result in functionality equivalent to the reference
224  * tape simulator. The NDMP TAPE model is demanding, and it is
225  * often necessary to workaround the native device driver(s)
226  * to achieve NDMP TAPE model conformance.
227  *
228  * It's easy to test this ndmos_tape_xxx() implementation
229  * using the ndmjob(1) command in test-tape conformance mode.
230  * The tape simulator passes this test. To test this implementation,
231  * rebuild ndmjob, then use this command:
232  *
233  *	ndmjob -o test-tape -T. -f /dev/whatever
234  *
235  * These ndmos_tape_xxx() interfaces must maintain the tape state
236  * (sess->tape_agent.tape_state). In particular, the position
237  * information (file_num and blockno) must be accurate at all
238  * times. A typical workaround is to maintain these here rather
239  * than relying on the native device drivers. Another workaround
240  * is to implement NDMP MTIO operations using repeated native MTIO
241  * operations with count=1, then interpret the results and errors
242  * to maintain accurate position and residual information.
243  *
244  * Workarounds in this implementation (please keep this updated):
245  *
246  */
247 
248 int
ndmos_tape_initialize(struct ndm_session * sess)249 ndmos_tape_initialize (struct ndm_session *sess)
250 {
251 	return -1;
252 }
253 
254 void
ndmos_tape_sync_state(struct ndm_session * sess)255 ndmos_tape_sync_state (struct ndm_session *sess)
256 {
257 	the_tape_state.error = NDMP9_DEV_NOT_OPEN_ERR;
258 }
259 
260 ndmp9_error
ndmos_tape_open(struct ndm_session * sess,char * name,int will_write)261 ndmos_tape_open (struct ndm_session *sess, char *name, int will_write)
262 {
263 	return NDMP9_NOT_SUPPORTED_ERR;
264 }
265 
266 ndmp9_error
ndmos_tape_close(struct ndm_session * sess)267 ndmos_tape_close (struct ndm_session *sess)
268 {
269 	return NDMP9_NOT_SUPPORTED_ERR;
270 }
271 
272 ndmp9_error
ndmos_tape_write(struct ndm_session * sess,char * data,unsigned long count,unsigned long * done_count)273 ndmos_tape_write (struct ndm_session *sess, char *data,
274   unsigned long count, unsigned long * done_count)
275 {
276 	return NDMP9_NOT_SUPPORTED_ERR;
277 }
278 
279 ndmp9_error
ndmos_tape_read(struct ndm_session * sess,char * data,unsigned long count,unsigned long * done_count)280 ndmos_tape_read (struct ndm_session *sess, char *data,
281   unsigned long count, unsigned long * done_count)
282 {
283 	return NDMP9_NOT_SUPPORTED_ERR;
284 }
285 
286 ndmp9_error
ndmos_tape_mtio(struct ndm_session * sess,ndmp9_tape_mtio_op op,unsigned long count,unsigned long * done_count)287 ndmos_tape_mtio (struct ndm_session *sess, ndmp9_tape_mtio_op op,
288   unsigned long count, unsigned long * done_count)
289 {
290 	return NDMP9_NOT_SUPPORTED_ERR;
291 }
292 
293 ndmp9_error
ndmos_tape_execute_cdb(struct ndm_session * sess,ndmp9_execute_cdb_request * request,ndmp9_execute_cdb_reply * reply)294 ndmos_tape_execute_cdb (struct ndm_session *sess,
295   ndmp9_execute_cdb_request *request,
296   ndmp9_execute_cdb_reply *reply)
297 {
298 	return NDMP9_NOT_SUPPORTED_ERR;
299 }
300 
301 #endif /* !NDMOS_OPTION_TAPE_SIMULATOR */
302 #else /* !NDMOS_OPTION_NO_TAPE_AGENT */
303 /* tape interfaces implemented in ndma_tape_simulator.c */
304 #endif /* !NDMOS_OPTION_NO_TAPE_AGENT */
305 #endif /* NDMOS_COMMON_TAPE_INTERFACE */
306 
307 
308 #ifdef NDMOS_COMMON_ROBOT_INTERFACE
309 #ifndef NDMOS_OPTION_NO_ROBOT_AGENT
310 #ifndef NDMOS_OPTION_ROBOT_SIMULATOR
311 
312 /* ndmos_robot_* functions here */
313 
314 #endif /* !NDMOS_OPTION_ROBOT_SIMULATOR */
315 #else /* !NDMOS_OPTION_NO_ROBOT_AGENT */
316 /* robot interfaces implemented in ndma_robot_simulator.c */
317 #endif /* !NDMOS_OPTION_NO_ROBOT_AGENT */
318 #endif /* NDMOS_COMMON_ROBOT_INTERFACE */
319 
320 
321 #ifdef NDMOS_COMMON_SCSI_INTERFACE
322 #ifndef NDMOS_OPTION_NO_ROBOT_AGENT	/* Surrounds all SCSI intfs */
323 #ifndef NDMOS_OPTION_ROBOT_SIMULATOR
324 /*
325  * SCSI INTERFACE
326  ****************************************************************
327  */
328 
329 int
ndmos_scsi_initialize(struct ndm_session * sess)330 ndmos_scsi_initialize (struct ndm_session *sess)
331 {
332 	return -1;
333 }
334 
335 void
ndmos_scsi_sync_state(struct ndm_session * sess)336 ndmos_scsi_sync_state (struct ndm_session *sess)
337 {
338 	sess->robot_acb.scsi_state.error = NDMP9_DEV_NOT_OPEN_ERR;
339 }
340 
341 ndmp9_error
ndmos_scsi_open(struct ndm_session * sess,char * name)342 ndmos_scsi_open (struct ndm_session *sess, char *name)
343 {
344 	return NDMP9_NOT_SUPPORTED_ERR;
345 }
346 
347 ndmp9_error
ndmos_scsi_close(struct ndm_session * sess)348 ndmos_scsi_close (struct ndm_session *sess)
349 {
350 	return NDMP9_NOT_SUPPORTED_ERR;
351 }
352 
353 /* deprecated */
354 ndmp9_error
ndmos_scsi_set_target(struct ndm_session * sess)355 ndmos_scsi_set_target (struct ndm_session *sess)
356 {
357 	return NDMP9_NOT_SUPPORTED_ERR;
358 }
359 
360 
361 ndmp9_error
ndmos_scsi_reset_device(struct ndm_session * sess)362 ndmos_scsi_reset_device (struct ndm_session *sess)
363 {
364 	return NDMP9_NOT_SUPPORTED_ERR;
365 }
366 
367 /* deprecated */
368 ndmp9_error
ndmos_scsi_reset_bus(struct ndm_session * sess)369 ndmos_scsi_reset_bus (struct ndm_session *sess)
370 {
371 	return NDMP9_NOT_SUPPORTED_ERR;
372 }
373 
374 ndmp9_error
ndmos_scsi_execute_cdb(struct ndm_session * sess,ndmp9_execute_cdb_request * request,ndmp9_execute_cdb_reply * reply)375 ndmos_scsi_execute_cdb (struct ndm_session *sess,
376   ndmp9_execute_cdb_request *request,
377   ndmp9_execute_cdb_reply *reply)
378 {
379 	return NDMP9_NOT_SUPPORTED_ERR;
380 }
381 
382 #endif /* NDMOS_OPTION_ROBOT_SIMULATOR */
383 #endif /* NDMOS_OPTION_NO_ROBOT_AGENT	Surrounds all SCSI intfs */
384 #endif /* NDMOS_COMMON_SCSI_INTERFACE */
385 
386 
387 
388 
389 #ifdef NDMOS_COMMON_DISPATCH_REQUEST
390 /*
391  * ndmos_dispatch_request() -- O/S Specific Agent Dispatch Request (ADR)
392  ****************************************************************
393  * Some NDMP requests can only be handled as O/S specific portions,
394  * and are implemented here.
395  *
396  * The more generic NDMP requests may be re-implemented here rather
397  * than modifying the main body of code. Extensions to the NDMP protocol
398  * may also be implemented here. Neither is ever a good idea beyond
399  * experimentation. The structures in ndmagents.h provide for O/S
400  * specific extensions. Such extensions are #define'd in the ndmos_xxx.h.
401  *
402  * The return value from ndmos_dispatch_request() tells the main
403  * dispatcher, ndma_dispatch_request(), whether or not the request
404  * was intercepted. ndmos_dispatch_request() is called after basic
405  * reply setup is done (message headers and buffers), but before
406  * the request is interpretted.
407  */
408 
409 #ifndef I_HAVE_DISPATCH_REQUEST
410 
411 /*
412  * If we're not intercepting, keep it simple
413  */
414 int
ndmos_dispatch_request(struct ndm_session * sess,struct ndmp_xa_buf * xa,struct ndmconn * ref_conn)415 ndmos_dispatch_request (struct ndm_session *sess,
416   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
417 {
418 	return -1;	/* not intercepted */
419 }
420 
421 #else /* !I_HAVE_DISPATCH_REQUEST */
422 
423 /*
424  * The following fragment is here for reference.
425  * If the O/S module intercepts requests, copy
426  * all this into the module source file and
427  * #undef NDMOS_COMMON_DISPATCH_REQUEST.
428  */
429 
430 extern struct ndm_dispatch_version_table ndmos_dispatch_version_table[];
431 
432 int
ndmos_dispatch_request(struct ndm_session * sess,struct ndmp_xa_buf * xa,struct ndmconn * ref_conn)433 ndmos_dispatch_request (struct ndm_session *sess,
434   struct ndmp_xa_buf *xa, struct ndmconn *ref_conn)
435 {
436 	struct ndm_dispatch_request_table *drt;
437 	unsigned	protocol_version = ref_conn->protocol_version;
438 	unsigned	msg = xa->request.header.message;
439 	int		rc;
440 
441 	drt = ndma_drt_lookup (ndmos_dispatch_version_table,
442 					protocol_version, msg);
443 
444 	if (!drt) {
445 		return -1;	/* not intercepted */
446 	}
447 
448 	/*
449 	 * Replicate the ndma_dispatch_request() permission checks
450 	 */
451 	if (!sess->conn_open
452 	 && !(drt->flags & NDM_DRT_FLAG_OK_NOT_CONNECTED)) {
453 		xa->reply.header.error = NDMP0_PERMISSION_ERR;
454 		return 0;
455 	}
456 
457 	if (!sess->conn_authorized
458 	 && !(drt->flags & NDM_DRT_FLAG_OK_NOT_AUTHORIZED)) {
459 		xa->reply.header.error = NDMP9_NOT_AUTHORIZED_ERR;
460 		return 0;
461 	}
462 
463 	rc = (*drt->dispatch_request)(sess, xa, ref_conn);
464 
465 	if (rc < 0) {
466 		xa->reply.header.error = NDMP0_NOT_SUPPORTED_ERR;
467 	}
468 
469 	return 0;
470 }
471 
472 
473 
474 
475 /*
476  * Dispatch Version Table and Dispatch Request Tables (DVT/DRT)
477  ****************************************************************
478  */
479 
480 struct ndm_dispatch_request_table ndmos_dispatch_request_table_v0[] = {
481    {0}
482 };
483 
484 #ifndef NDMOS_OPTION_NO_NDMP2
485 struct ndm_dispatch_request_table ndmos_dispatch_request_table_v2[] = {
486    {0}
487 };
488 #endif /* !NDMOS_OPTION_NO_NDMP2 */
489 
490 #ifndef NDMOS_OPTION_NO_NDMP3
491 struct ndm_dispatch_request_table ndmos_dispatch_request_table_v3[] = {
492    {0}
493 };
494 #endif /* !NDMOS_OPTION_NO_NDMP3 */
495 
496 #ifndef NDMOS_OPTION_NO_NDMP4
497 struct ndm_dispatch_request_table ndmos_dispatch_request_table_v4[] = {
498    {0}
499 };
500 #endif /* !NDMOS_OPTION_NO_NDMP4 */
501 
502 
503 struct ndm_dispatch_version_table ndmos_dispatch_version_table[] = {
504 	{ 0,		ndmos_dispatch_request_table_v0 },
505 #ifndef NDMOS_OPTION_NO_NDMP2
506 	{ NDMP2VER,	ndmos_dispatch_request_table_v2 },
507 #endif /* !NDMOS_OPTION_NO_NDMP2 */
508 #ifndef NDMOS_OPTION_NO_NDMP3
509 	{ NDMP3VER,	ndmos_dispatch_request_table_v3 },
510 #endif /* !NDMOS_OPTION_NO_NDMP2 */
511 #ifndef NDMOS_OPTION_NO_NDMP4
512 	{ NDMP4VER,	ndmos_dispatch_request_table_v4 },
513 #endif /* !NDMOS_OPTION_NO_NDMP4 */
514 	{ -1 }
515 };
516 #endif /* !I_HAVE_DISPATCH_REQUEST */
517 #endif /* NDMOS_COMMON_DISPATCH_REQUEST */
518