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  * CONFIG SUPPORT
52  ****************************************************************
53  */
54 
55 #ifdef NDMOS_COMMON_SYNC_CONFIG_INFO
56 #include "lib/version.h"
57 /*
58  * Get local info. Supports NDMPx_CONFIG_GET_HOST_INFO,
59  * NDMP3_CONFIG_GET_SERVER_INFO, and NDMPx_CONFIG_GET_SCSI_INFO.
60  */
ndmos_sync_config_info(struct ndm_session * sess)61 void ndmos_sync_config_info(struct ndm_session* sess)
62 {
63   static struct utsname unam;
64   static char osbuf[150];
65   static char idbuf[30];
66   static char revbuf[100];
67   char obuf[5];
68 
69   if (!sess->config_info) {
70     sess->config_info =
71         (ndmp9_config_info*)NDMOS_API_MALLOC(sizeof(ndmp9_config_info));
72     if (!sess->config_info) return;
73     NDMOS_MACRO_ZEROFILL(sess->config_info);
74   }
75 
76   if (sess->config_info->hostname) {
77     /* already set */
78     return;
79   }
80 
81   obuf[0] = (char)(NDMOS_ID >> 24);
82   obuf[1] = (char)(NDMOS_ID >> 16);
83   obuf[2] = (char)(NDMOS_ID >> 8);
84   obuf[3] = (char)(NDMOS_ID >> 0);
85   obuf[4] = 0;
86 
87   uname(&unam);
88   snprintf(idbuf, sizeof(idbuf), "%lu", gethostid());
89   /*
90    * give CONTROL via NDMPv2 a chance to recognize this
91    * implementation (no ndmp2_config_get_server).
92    */
93   snprintf(osbuf, sizeof(osbuf), "%s (running %s from %s)", unam.sysname,
94            NDMOS_CONST_PRODUCT_NAME, NDMOS_CONST_VENDOR_NAME);
95 
96   sess->config_info->hostname = unam.nodename;
97   sess->config_info->os_type = osbuf;
98   sess->config_info->os_vers = unam.release;
99   sess->config_info->hostid = idbuf;
100 
101   sess->config_info->vendor_name = (char*)NDMOS_CONST_VENDOR_NAME;
102   sess->config_info->product_name = (char*)NDMOS_CONST_PRODUCT_NAME;
103 
104   snprintf(revbuf, sizeof(revbuf), "%s LIB:%d.%d/%s OS:%s (%s)",
105            kBareosVersionStrings.Full, NDMJOBLIB_VERSION, NDMJOBLIB_RELEASE,
106            kBareosVersionStrings.Full, NDMOS_CONST_NDMOS_REVISION, obuf);
107 
108   sess->config_info->revision_number = revbuf;
109 
110   /* best effort; note that this loads scsi and tape config */
111   if (sess->param->config_file_name)
112     ndmcfg_load(sess->param->config_file_name, sess->config_info);
113 }
114 #endif /* NDMOS_COMMON_SYNC_CONFIG_INFO */
115 
116 
117 /*
118  * AUTHENTICATION SUPPORT
119  ****************************************************************
120  */
121 
ndmos_auth_register_callbacks(struct ndm_session * sess,struct ndm_auth_callbacks * callbacks)122 void ndmos_auth_register_callbacks(struct ndm_session* sess,
123                                    struct ndm_auth_callbacks* callbacks)
124 {
125   /*
126    * Only allow one register.
127    */
128   if (!sess->nac) {
129     sess->nac = (struct ndm_auth_callbacks*)NDMOS_API_MALLOC(
130         sizeof(struct ndm_auth_callbacks));
131     if (sess->nac) {
132       memcpy(sess->nac, callbacks, sizeof(struct ndm_auth_callbacks));
133     }
134   }
135 }
136 
ndmos_auth_unregister_callbacks(struct ndm_session * sess)137 void ndmos_auth_unregister_callbacks(struct ndm_session* sess)
138 {
139   if (sess->nac) {
140     NDMOS_API_FREE(sess->nac);
141     sess->nac = NULL;
142   }
143 }
144 
145 #ifdef NDMOS_COMMON_OK_NAME_PASSWORD
146 /*
147  * Determine whether the clear-text account name and password
148  * are valid. Supports NDMPx_CONNECT_CLIENT_AUTH requests.
149  */
ndmos_ok_name_password(struct ndm_session * sess,char * name,char * pass)150 int ndmos_ok_name_password(struct ndm_session* sess, char* name, char* pass)
151 {
152   if (sess->nac && sess->nac->validate_password) {
153     return sess->nac->validate_password(sess, name, pass);
154   }
155   return 0; /* NOT OK */
156 }
157 #endif /* NDMOS_COMMON_OK_NAME_PASSWORD */
158 
159 
160 #ifdef NDMOS_COMMON_MD5
161 /*
162  * MD5 authentication support
163  *
164  * See ndml_md5.c
165  */
166 
ndmos_get_md5_challenge(struct ndm_session * sess)167 int ndmos_get_md5_challenge(struct ndm_session* sess)
168 {
169   ndmmd5_generate_challenge(sess->md5_challenge);
170   sess->md5_challenge_valid = 1;
171   return 0;
172 }
173 
ndmos_ok_name_md5_digest(struct ndm_session * sess,char * name,char digest[16])174 int ndmos_ok_name_md5_digest(struct ndm_session* sess,
175                              char* name,
176                              char digest[16])
177 {
178   if (sess->nac && sess->nac->validate_md5) {
179     return sess->nac->validate_md5(sess, name, digest);
180   }
181   return 0; /* NOT OK */
182 }
183 #endif /* NDMOS_COMMON_MD5 */
184 
185 
186 #ifdef NDMOS_COMMON_NONBLOCKING_IO_SUPPORT
187 /*
188  * NON-BLOCKING I/O SUPPORT
189  ****************************************************************
190  * As support non-blocking I/O for NDMCHAN, condition different
191  * types of file descriptors to not block.
192  */
193 
ndmos_condition_listen_socket(struct ndm_session * sess,int sock)194 void ndmos_condition_listen_socket(struct ndm_session* sess, int sock)
195 {
196   int flag;
197 
198   flag = 1;
199   setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*)&flag, sizeof flag);
200 }
201 
ndmos_condition_control_socket(struct ndm_session * sess,int sock)202 void ndmos_condition_control_socket(struct ndm_session* sess, int sock)
203 {
204   /* nothing */
205 }
206 
ndmos_condition_image_stream_socket(struct ndm_session * sess,int sock)207 void ndmos_condition_image_stream_socket(struct ndm_session* sess, int sock)
208 {
209   fcntl(sock, F_SETFL, O_NONBLOCK);
210   signal(SIGPIPE, SIG_IGN);
211 }
212 
ndmos_condition_pipe_fd(struct ndm_session * sess,int fd)213 void ndmos_condition_pipe_fd(struct ndm_session* sess, int fd)
214 {
215   fcntl(fd, F_SETFL, O_NONBLOCK);
216   signal(SIGPIPE, SIG_IGN);
217 }
218 #endif /* NDMOS_COMMON_NONBLOCKING_IO_SUPPORT */
219 
220 
221 #ifdef NDMOS_COMMON_TAPE_INTERFACE
222 #ifndef NDMOS_OPTION_NO_TAPE_AGENT
223 #ifndef NDMOS_OPTION_TAPE_SIMULATOR
224 /*
225  * TAPE INTERFACE
226  ****************************************************************
227  * These interface to the O/S specific tape drivers and subsystem.
228  * They must result in functionality equivalent to the reference
229  * tape simulator. The NDMP TAPE model is demanding, and it is
230  * often necessary to workaround the native device driver(s)
231  * to achieve NDMP TAPE model conformance.
232  *
233  * It's easy to test this ndmos_tape_xxx() implementation
234  * using the ndmjob(1) command in test-tape conformance mode.
235  * The tape simulator passes this test. To test this implementation,
236  * rebuild ndmjob, then use this command:
237  *
238  *      ndmjob -o test-tape -T. -f /dev/whatever
239  *
240  * These ndmos_tape_xxx() interfaces must maintain the tape state
241  * (sess->tape_agent.tape_state). In particular, the position
242  * information (file_num and blockno) must be accurate at all
243  * times. A typical workaround is to maintain these here rather
244  * than relying on the native device drivers. Another workaround
245  * is to implement NDMP MTIO operations using repeated native MTIO
246  * operations with count=1, then interpret the results and errors
247  * to maintain accurate position and residual information.
248  *
249  * Workarounds in this implementation (please keep this updated):
250  *
251  */
252 
ndmos_tape_initialize(struct ndm_session * sess)253 int ndmos_tape_initialize(struct ndm_session* sess) { return -1; }
254 
ndmos_tape_sync_state(struct ndm_session * sess)255 void ndmos_tape_sync_state(struct ndm_session* sess)
256 {
257   struct ndm_tape_agent* ta = sess->tape_acb;
258 
259   ta->tape_state.error = NDMP9_DEV_NOT_OPEN_ERR;
260 }
261 
ndmos_tape_open(struct ndm_session * sess,char * name,int will_write)262 ndmp9_error ndmos_tape_open(struct ndm_session* sess,
263                             char* name,
264                             int will_write)
265 {
266   return NDMP9_NOT_SUPPORTED_ERR;
267 }
268 
ndmos_tape_close(struct ndm_session * sess)269 ndmp9_error ndmos_tape_close(struct ndm_session* sess)
270 {
271   return NDMP9_NOT_SUPPORTED_ERR;
272 }
273 
ndmos_tape_write(struct ndm_session * sess,char * data,uint32_t count,uint32_t * done_count)274 ndmp9_error ndmos_tape_write(struct ndm_session* sess,
275                              char* data,
276                              uint32_t count,
277                              uint32_t* done_count)
278 {
279   return NDMP9_NOT_SUPPORTED_ERR;
280 }
281 
ndmos_tape_read(struct ndm_session * sess,char * data,uint32_t count,uint32_t * done_count)282 ndmp9_error ndmos_tape_read(struct ndm_session* sess,
283                             char* data,
284                             uint32_t count,
285                             uint32_t* done_count)
286 {
287   return NDMP9_NOT_SUPPORTED_ERR;
288 }
289 
ndmos_tape_mtio(struct ndm_session * sess,ndmp9_tape_mtio_op op,uint32_t count,uint32_t * done_count)290 ndmp9_error ndmos_tape_mtio(struct ndm_session* sess,
291                             ndmp9_tape_mtio_op op,
292                             uint32_t count,
293                             uint32_t* done_count)
294 {
295   return NDMP9_NOT_SUPPORTED_ERR;
296 }
297 
ndmos_tape_execute_cdb(struct ndm_session * sess,ndmp9_execute_cdb_request * request,ndmp9_execute_cdb_reply * reply)298 ndmp9_error ndmos_tape_execute_cdb(struct ndm_session* sess,
299                                    ndmp9_execute_cdb_request* request,
300                                    ndmp9_execute_cdb_reply* reply)
301 {
302   return NDMP9_NOT_SUPPORTED_ERR;
303 }
304 
305 #endif /* !NDMOS_OPTION_TAPE_SIMULATOR */
306 #else  /* !NDMOS_OPTION_NO_TAPE_AGENT */
307 /* tape interfaces implemented in ndma_tape_simulator.c */
308 #endif /* !NDMOS_OPTION_NO_TAPE_AGENT */
309 #endif /* NDMOS_COMMON_TAPE_INTERFACE */
310 
311 
312 #ifdef NDMOS_COMMON_ROBOT_INTERFACE
313 #ifndef NDMOS_OPTION_NO_ROBOT_AGENT
314 #ifndef NDMOS_OPTION_ROBOT_SIMULATOR
315 
316 /* ndmos_robot_* functions here */
317 
318 #endif /* !NDMOS_OPTION_ROBOT_SIMULATOR */
319 #else  /* !NDMOS_OPTION_NO_ROBOT_AGENT */
320 /* robot interfaces implemented in ndma_robot_simulator.c */
321 #endif /* !NDMOS_OPTION_NO_ROBOT_AGENT */
322 #endif /* NDMOS_COMMON_ROBOT_INTERFACE */
323 
324 
325 #ifdef NDMOS_COMMON_SCSI_INTERFACE
326 #ifndef NDMOS_OPTION_NO_ROBOT_AGENT /* Surrounds all SCSI intfs */
327 #ifndef NDMOS_OPTION_ROBOT_SIMULATOR
328 /*
329  * SCSI INTERFACE
330  ****************************************************************
331  */
332 
ndmos_scsi_initialize(struct ndm_session * sess)333 int ndmos_scsi_initialize(struct ndm_session* sess) { return -1; }
334 
ndmos_scsi_sync_state(struct ndm_session * sess)335 void ndmos_scsi_sync_state(struct ndm_session* sess)
336 {
337   sess->robot_acb->scsi_state.error = NDMP9_DEV_NOT_OPEN_ERR;
338 }
339 
ndmos_scsi_open(struct ndm_session * sess,char * name)340 ndmp9_error ndmos_scsi_open(struct ndm_session* sess, char* name)
341 {
342   return NDMP9_NOT_SUPPORTED_ERR;
343 }
344 
ndmos_scsi_close(struct ndm_session * sess)345 ndmp9_error ndmos_scsi_close(struct ndm_session* sess)
346 {
347   return NDMP9_NOT_SUPPORTED_ERR;
348 }
349 
350 /* deprecated */
ndmos_scsi_set_target(struct ndm_session * sess)351 ndmp9_error ndmos_scsi_set_target(struct ndm_session* sess)
352 {
353   return NDMP9_NOT_SUPPORTED_ERR;
354 }
355 
356 
ndmos_scsi_reset_device(struct ndm_session * sess)357 ndmp9_error ndmos_scsi_reset_device(struct ndm_session* sess)
358 {
359   return NDMP9_NOT_SUPPORTED_ERR;
360 }
361 
362 /* deprecated */
ndmos_scsi_reset_bus(struct ndm_session * sess)363 ndmp9_error ndmos_scsi_reset_bus(struct ndm_session* sess)
364 {
365   return NDMP9_NOT_SUPPORTED_ERR;
366 }
367 
ndmos_scsi_execute_cdb(struct ndm_session * sess,ndmp9_execute_cdb_request * request,ndmp9_execute_cdb_reply * reply)368 ndmp9_error ndmos_scsi_execute_cdb(struct ndm_session* sess,
369                                    ndmp9_execute_cdb_request* request,
370                                    ndmp9_execute_cdb_reply* reply)
371 {
372   return NDMP9_NOT_SUPPORTED_ERR;
373 }
374 
375 #endif /* NDMOS_OPTION_ROBOT_SIMULATOR */
376 #endif /* NDMOS_OPTION_NO_ROBOT_AGENT   Surrounds all SCSI intfs */
377 #endif /* NDMOS_COMMON_SCSI_INTERFACE */
378 
379 
380 #ifdef NDMOS_COMMON_DISPATCH_REQUEST
381 /*
382  * ndmos_dispatch_request() -- O/S Specific Agent Dispatch Request (ADR)
383  ****************************************************************
384  * Some NDMP requests can only be handled as O/S specific portions,
385  * and are implemented here.
386  *
387  * The more generic NDMP requests may be re-implemented here rather
388  * than modifying the main body of code. Extensions to the NDMP protocol
389  * may also be implemented here. Neither is ever a good idea beyond
390  * experimentation. The structures in ndmagents.h provide for O/S
391  * specific extensions. Such extensions are #define'd in the ndmos_xxx.h.
392  *
393  * The return value from ndmos_dispatch_request() tells the main
394  * dispatcher, ndma_dispatch_request(), whether or not the request
395  * was intercepted. ndmos_dispatch_request() is called after basic
396  * reply setup is done (message headers and buffers), but before
397  * the request is interpretted.
398  */
399 
400 #ifndef I_HAVE_DISPATCH_REQUEST
401 
402 /*
403  * If we're not intercepting, keep it simple
404  */
ndmos_dispatch_request(struct ndm_session * sess,struct ndmp_xa_buf * xa,struct ndmconn * ref_conn)405 int ndmos_dispatch_request(struct ndm_session* sess,
406                            struct ndmp_xa_buf* xa,
407                            struct ndmconn* ref_conn)
408 {
409   return -1; /* not intercepted */
410 }
411 
412 #else /* !I_HAVE_DISPATCH_REQUEST */
413 
414 /*
415  * The following fragment is here for reference.
416  * If the O/S module intercepts requests, copy
417  * all this into the module source file and
418  * #undef NDMOS_COMMON_DISPATCH_REQUEST.
419  */
420 
421 extern struct ndm_dispatch_version_table ndmos_dispatch_version_table[];
422 
ndmos_dispatch_request(struct ndm_session * sess,struct ndmp_xa_buf * xa,struct ndmconn * ref_conn)423 int ndmos_dispatch_request(struct ndm_session* sess,
424                            struct ndmp_xa_buf* xa,
425                            struct ndmconn* ref_conn)
426 {
427   struct ndm_dispatch_request_table* drt;
428   unsigned protocol_version = ref_conn->protocol_version;
429   unsigned msg = xa->request.header.message;
430   int rc;
431 
432   drt = ndma_drt_lookup(ndmos_dispatch_version_table, protocol_version, msg);
433 
434   if (!drt) { return -1; /* not intercepted */ }
435 
436   /*
437    * Replicate the ndma_dispatch_request() permission checks
438    */
439   if (!sess->conn_open && !(drt->flags & NDM_DRT_FLAG_OK_NOT_CONNECTED)) {
440     xa->reply.header.error = NDMP0_PERMISSION_ERR;
441     return 0;
442   }
443 
444   if (!sess->conn_authorized &&
445       !(drt->flags & NDM_DRT_FLAG_OK_NOT_AUTHORIZED)) {
446     xa->reply.header.error = NDMP9_NOT_AUTHORIZED_ERR;
447     return 0;
448   }
449 
450   rc = (*drt->dispatch_request)(sess, xa, ref_conn);
451 
452   if (rc < 0) { xa->reply.header.error = NDMP0_NOT_SUPPORTED_ERR; }
453 
454   return 0;
455 }
456 
457 
458 /*
459  * Dispatch Version Table and Dispatch Request Tables (DVT/DRT)
460  ****************************************************************
461  */
462 
463 struct ndm_dispatch_request_table ndmos_dispatch_request_table_v0[] = {{0}};
464 
465 #ifndef NDMOS_OPTION_NO_NDMP2
466 struct ndm_dispatch_request_table ndmos_dispatch_request_table_v2[] = {{0}};
467 #endif /* !NDMOS_OPTION_NO_NDMP2 */
468 
469 #ifndef NDMOS_OPTION_NO_NDMP3
470 struct ndm_dispatch_request_table ndmos_dispatch_request_table_v3[] = {{0}};
471 #endif /* !NDMOS_OPTION_NO_NDMP3 */
472 
473 #ifndef NDMOS_OPTION_NO_NDMP4
474 struct ndm_dispatch_request_table ndmos_dispatch_request_table_v4[] = {{0}};
475 #endif /* !NDMOS_OPTION_NO_NDMP4 */
476 
477 
478 struct ndm_dispatch_version_table ndmos_dispatch_version_table[] = {
479     {0, ndmos_dispatch_request_table_v0},
480 #ifndef NDMOS_OPTION_NO_NDMP2
481     {NDMP2VER, ndmos_dispatch_request_table_v2},
482 #endif /* !NDMOS_OPTION_NO_NDMP2 */
483 #ifndef NDMOS_OPTION_NO_NDMP3
484     {NDMP3VER, ndmos_dispatch_request_table_v3},
485 #endif /* !NDMOS_OPTION_NO_NDMP2 */
486 #ifndef NDMOS_OPTION_NO_NDMP4
487     {NDMP4VER, ndmos_dispatch_request_table_v4},
488 #endif /* !NDMOS_OPTION_NO_NDMP4 */
489     {-1}};
490 #endif /* !I_HAVE_DISPATCH_REQUEST */
491 #endif /* NDMOS_COMMON_DISPATCH_REQUEST */
492