/** ** ============================== ** OOOO O O OOOO ** O O O O O O O ** O O O O O O O ** OOOO OOOO O OOO OOOO ** O O O O O O O ** O O O O O O O ** OOOO OOOO O O OOOO ** ============================== ** Dr. Stefan Bosse http://www.bsslab.de ** ** COPYRIGHT: THIS SOFTWARE, EXECUTABLE AND SOURCE CODE IS OWNED ** BY THE AUTHOR(S). ** THIS SOURCE CODE MAY NOT BE COPIED, EXTRACTED, ** MODIFIED, OR OTHERWISE USED IN A CONTEXT ** OUTSIDE OF THE SOFTWARE SYSTEM. ** ** $AUTHORS: Stefan Bosse ** $INITIAL: (C) 2006-2016 BSSLAB ** $CREATED: 7/7/15 by sbosse. ** $VERSION: 1.2.4 ** ** $INFO: ** ** DOS: DNS RPC Interface ** ** $ENDOFINFO */ /* ********************* ** PUBLIC INTERFACE ********************* */ "use strict"; var log = 0; var util = Require('util'); var Io = Require('com/io'); var Net = Require('dos/network'); var Status = Net.Status; var Command = Net.Command; var Rights = Net.Rights; var Std = Require('dos/std'); var Sch = Require('dos/scheduler'); var Buf = Require('dos/buf'); var Rpc = Require('dos/rpc'); var Fs = Require('fs'); var Comp = Require('com/compat'); var String = Comp.string; var Array = Comp.array; var Perv = Comp.pervasives; var Hashtbl = Comp.hashtbl; var Filename = Comp.filename; var assert = Comp.assert; var div = Comp.div; var Afs = Require('dos/afs_srv_common'); var Afs_file_state = Afs.Afs_file_state; var Afs_commit_flag= Afs.Afs_commit_flag; var DnsInt = Require('dos/dns'); var Dns = Require('dos/dns_srv_common'); var Cs = Require('dos/capset'); /** * @augments dns_server * @augments dns_server_emb * @see dns_server * @see dns_server_emb * @see dns_server_rpc~meth * @constructor */ var dns_server_rpc = function() { }; /** * @typedef {{ * dns_lookup:dns_server.dns_lookup, * dns_create:dns_server.dns_create, * dns_append:dns_server.dns_append, * dns_info:dns_server.dns_info, * dns_stat:dns_server.dns_stat, * dns_list:dns_server.dns_list, * dns_setlookup:dns_server.dns_setlookup}} dns_server_emb~meth * /** ** DNS_LOOKUP: ** Traverse a path as far as possible, and return the resulting (restricted) capability ** set and the rest of the path. * * @param {private} priv * @param {string} path * @param {function((Status.STD_OK|*),capset|undefined,string)} callback */ dns_server_rpc.prototype.dns_lookup = function(priv,path,callback) { var self=this; //var log=1; var path = Filename.path_normalize(path); var path_rel = Filename.is_relative(path); var pathl = String.split ('/', path); var finished = false; /* ** Avoid recursion. Visit each directory only once! */ var visited=[]; Io.log((log<1)||('Dns_server.dns_lookup '+Net.Print.private(priv))); /* ** During we iterate over the path components, this ** rights value will be adjusted with the rights from the ** path components and used finally to restrict the ** capability set of the last path component ** resolved by this server. */ var have_rights = Rights.PRV_ALL_RIGHTS; var rights = Net.prv_rights(priv); /** * * @type {dns_dir|undefined} */ var dir = undefined; /** * * @type {dns_dir|undefined} */ var dir_last = undefined; /** * * @type {dns_row|undefined} */ var row_last = undefined; var stat= Status.STD_OK; var mask = rights & Rights.PRV_ALL_RIGHTS; var colmask=0; var cs; Sch.ScheduleBlock([ /* ** The root directory for the iteration... */ function () {self.request_dir(priv,Rights.DNS_RGT_READ,function (_stat,_dir) { Io.log((log<1)||('Dns_server.dns_lookup request_dir: '+Status.print(_stat))); stat=_stat; dir=_dir; })}, function () { var i; if (stat!=Status.STD_OK) throw stat; dir_last=dir; visited.push(dir.dd_objnum); Sch.ScheduleLoop(function(index){ return !finished && stat==Status.STD_OK; },[ function () { Array.match(pathl,function (hd,tl) { pathl = tl; dir_last = dir; /* ** When checking the presence of column rights, only take ** the *actual* columns present into account, ** so do not use DNS_COLMASK here. */ var ncols = dir.dd_ncols; var colrights=Dns.dns_col_bits[ncols]-1; /* ** The columns mask for the calculation for the ** next lookup, if any, ** and the permission for the row lookup in the current ** directory. ** The current have_rights are logical ** and-ed with the current mask (limited to ncol bits). */ colmask= mask & have_rights & colrights; Io.log((log<1)||('Dns_server.dns_lookup: rowname='+hd+' colrights='+colrights+' have_rights='+have_rights+' mask='+mask+' colmask='+colmask)); if (colmask==0) { self.release_unmodified_dir(dir); throw Status.STD_DENIED; } var row = self.search_row(dir,hd); if (row==undefined) { self.release_unmodified_dir(dir); dir_last=undefined; throw Status.STD_NOTFOUND; } row_last=row; /* ** Calculate the new have_rights value. ** All the columns rights from the current row ** are logical or-ed,if, and only if the i-th ** bit in the current column mask is set. ** The i-th bit corresponds to the i-th rights column ** in the current row. */ var colmasknew=0; var cols = row.dr_columns; for(i=0;i Dns.DNS_MAXCOLUMNS) { callback(Status.STD_ARGBAD,undefined); return; } var dir=undefined; var new_dir=undefined; var stat=Status.STD_UNKNOWN; Sch.ScheduleBlock([ function () { self.request_dir(priv,Rights.DNS_RGT_CREATE,function (_stat,_dir) { stat=_stat; dir=_dir; }) }, function () { if (stat != Status.STD_OK) throw stat; self.release_unmodified_dir(dir); self.alloc_dir(colnames,function (_stat,_dir) { stat=_stat; new_dir=_dir; }); }, function () { if (stat!=Status.STD_OK) throw Status.STD_NOSPACE; var cs=self.capset_of_dir(new_dir,Rights.PRV_ALL_RIGHTS); self.release_dir(new_dir,function (_stat) { if(_stat==Status.STD_OK) callback(Status.STD_OK,cs); else callback(_stat,undefined); }); } ],function (e) { if (typeof e != 'number') {Io.printstack(e,'Dns_server_rpc.dns_create');} if (typeof e == 'number') callback(e,undefined); else callback(Status.STD_SYSERR,undefined); }) }; /** Append a row to a directory. The name, right masks (cols), and initial ** capability set must be specified. * * @param priv * @param name * @param {number []} cols * @param {capset} cs * @param {function((Status.STD_OK|*))} callback */ dns_server_rpc.prototype.dns_append = function(priv,name,cols,cs,callback) { var self=this; var ncols=cols.length; var dir=undefined; var stat=Status.STD_UNKNOWN; if (ncols > Dns.DNS_MAXCOLUMNS || String.equal(name,'')) { callback(Status.STD_ARGBAD); return; } Sch.ScheduleBlock([ function () { Io.log((log<2)||('Dns_server.dns_append: request_dir '+Net.Print.private(priv))); self.request_dir(priv,Rights.DNS_RGT_MODIFY,function (_stat,_dir) { Io.log((log<2)||('Dns_server.dns_append: request_dir returns '+Status.print(_stat))); stat=_stat; dir=_dir; }) }, function () { if (stat != Status.STD_OK) throw stat; var row = self.search_row(dir,name); if (row!=undefined) throw Status.STD_EXISTS; var new_row = Dns.Dns_row(name,self.time(),cols,cs); self.append_row(dir,new_row); self.release_dir(dir,function (_stat) { callback(_stat); }); } ],function (e) { if (typeof e != 'number') {Io.printstack(e,'Dns_server_rpc.dns_append');} if (typeof e == 'number') callback(e); else callback(Status.STD_SYSERR); }) }; /** Rename a row of a directory. * * @param priv * @param oldname * @param newname * @param {function((Status.STD_OK|*))} callback */ dns_server_rpc.prototype.dns_rename = function(priv,oldname,newname,callback) { var self=this; var dir=undefined; var stat=Status.STD_UNKNOWN; if (String.equal(oldname,'') || String.equal(newname,'')) { callback(Status.STD_ARGBAD); return; } Sch.ScheduleBlock([ function () { self.request_dir(priv,Rights.DNS_RGT_MODIFY,function (_stat,_dir) { stat=_stat; dir=_dir; }) }, function () { if (stat != Status.STD_OK) { throw stat; } stat=self.rename_row(dir,oldname,newname); self.release_dir(dir,function (_stat) { if (stat==Status.STD_OK) callback(_stat); else callback(stat); }); } ],function (e) { if (typeof e != 'number') {Io.printstack(e,'Dns_server_rpc.dns_rename');} if (typeof e == 'number') callback(e); else callback(Status.STD_SYSERR); }) }; /** Change columns rights of a row in a directory. * * @param priv * @param rowname * @param {number []} cols * @param {function((Status.STD_OK|*))} callback */ dns_server_rpc.prototype.dns_chmod = function(priv,rowname,cols,callback) { var self=this; var dir=undefined; var row=undefined; var ncols=cols.length; var stat=Status.STD_UNKNOWN; if (String.equal(rowname,'') || Array.empty(cols)) { callback(Status.STD_ARGBAD); return; } Sch.ScheduleBlock([ function () { self.request_dir(priv,Rights.DNS_RGT_MODIFY,function (_stat,_dir) { stat=_stat; dir=_dir; }) }, function () { if (stat != Status.STD_OK) { throw stat; } row=self.search_row(dir,rowname); if (row==undefined) stat=Status.STD_NOTFOUND; else { stat=Status.STD_OK; var maxcols=Perv.min(Array.length(row.dr_columns),ncols); for(var i=0;i 0) { Io.inspect(name); Io.inspect(cs); Io.inspect(cols); } Sch.ScheduleBlock([ function () { dns.dns_append(rpcio.header.h_priv, name, cols, cs, function (_stat) { rpcio.header.h_status = _stat; Buf.buf_init(rpcio); Io.log((log < 1) || ('Dns_srv_rpc.DNS_APPEND returns: ' + Net.Status.print(_stat))); }); }]); Io.log((log < 1) || ('Dns_srv_rpc.DNS_APPEND passes through')); break; case Command.DNS_LOOKUP: Io.log((log < 1) || ('dns_srv_rpc.DNS_LOOKUP ' + Net.Print.private(rpcio.header.h_priv))); path = Buf.buf_get_string(rpcio); Sch.ScheduleBlock([ function () { dns.dns_lookup(rpcio.header.h_priv, path, function (_stat, _cs, _path) { Io.log((log < 1) || ('Dns_srv_rpc.DNS_LOOKUP returns: ' + Net.Status.print(_stat))); Buf.buf_init(rpcio); if (_stat == Status.STD_OK) { /* ** Put the path_rest string and the capability set. */ Buf.buf_put_string(rpcio, _path); Cs.buf_put_capset(rpcio, _cs); }; rpcio.header.h_status = _stat; }); }]); Io.log((log < 1) || ('Dns_srv_rpc.DNS_LOOKUP passes through')); break; case Command.DNS_RENAME: /* * ------------ * oldname:string * newname:string * ------------ * ------------ */ Io.log((log < 1) || ('Dns_srv_rpc.DNS_RENAME ' + Net.Print.private(rpcio.header.h_priv))); name = Buf.buf_get_string(rpcio); var newname = Buf.buf_get_string(rpcio); Sch.ScheduleBlock([ function () { dns.dns_rename(rpcio.header.h_priv, name, newname, function (_stat) { Buf.buf_init(rpcio); rpcio.header.h_status = _stat; }); }]); break; case Command.DNS_REPLACE: /* * ------------ * name:string * newcs:capset * ------------ * ------------ */ Io.log((log < 1) || ('Dns_srv_rpc.DNS_REPLACE ' + Net.Print.private(rpcio.header.h_priv))); name = Buf.buf_get_string(rpcio); var newcs = Cs.buf_get_capset(rpcio); Sch.ScheduleBlock([ function () { dns.dns_replace(rpcio.header.h_priv, name, newcs, function (_stat) { Buf.buf_init(rpcio); rpcio.header.h_status = _stat; }); }]); break; case Command.DNS_DELETE: /* * ------------ * rowname:string * ------------ * ------------ */ Io.log((log < 1) || ('Dns_srv_rpc.DNS_DELETE ' + Net.Print.private(rpcio.header.h_priv))); name = Buf.buf_get_string(rpcio); Sch.ScheduleBlock([ function () { dns.dns_delete(rpcio.header.h_priv, name, function (_stat) { Buf.buf_init(rpcio); rpcio.header.h_status = _stat; }); }]); break; case Command.DNS_CREATE: /* * ----- * ncols(int16) * [colname(string)] #ncols * ----- * cs(capset) * ----- */ Io.log((log < 1) || ('Dns_srv_rpc.DNS_CREATE ' + Net.Print.private(rpcio.header.h_priv))); ncols = Buf.buf_get_int16(rpcio); colnames = []; for (i = 0; i < ncols; i++) { colnames.push(Buf.buf_get_string(rpcio)); } Sch.ScheduleBlock([ function () { dns.dns_create(rpcio.header.h_priv, colnames, function (_stat, _cs) { Buf.buf_init(rpcio); rpcio.header.h_status = _stat; if (_stat == Status.STD_OK) { Cs.buf_put_capset(rpcio, _cs); } }); }]); break; case Command.DNS_CHMOD: /* * ----- * rowname(string) * ncols(int16) * cols: rights [] * ----- * ----- */ Io.log((log < 1) || ('Dns_srv_rpc.DNS_CHMOD ' + Net.Print.private(rpcio.header.h_priv))); ncols = Buf.buf_get_int16(rpcio); cols = []; for (i = 0; i < ncols; i++) { cols.push(DnsInt.buf_get_rights(rpcio)); } Sch.ScheduleBlock([ function () { dns.dns_chmod(rpcio.header.h_priv, cols, function (_stat) { Buf.buf_init(rpcio); rpcio.header.h_status = _stat; }); }]); break; case Command.DNS_LIST: /* * -------------- * rowoff(int16) * --------------- * next_row(int16) * ncols(int16) * nrows(int16) * colnames: [name(string)] #ncols * rows: [ * name(string) * time(int32) * [rights(int16)] #ncols * ] #nrows * -------------- */ Io.log((log < 1) || ('Dns_srv_rpc.DNS_LIST ' + Net.Print.private(rpcio.header.h_priv))); off = Buf.buf_get_int16(rpcio); rpcio.pos = 0; Sch.ScheduleBlock([ function () { dns.dns_list(rpcio.header.h_priv, off, 1000, function (_stat, nrows, ncols, colnames, rows) { rpcio.header.h_status = _stat; Buf.buf_init(rpcio); if (_stat == Status.STD_OK) { Buf.buf_put_int16(rpcio, DnsInt.DNS_NOMOREROWS); Buf.buf_put_int16(rpcio, ncols); Buf.buf_put_int16(rpcio, nrows); /* ** Push the column names */ Array.iter(colnames, function (col) { Buf.buf_put_string(rpcio, col); }); /* ** Assumption: all rows fit in one transaction */ Io.log((log < 1) || 'dnssrv.DNS_LIST #rows=' +rows.length); Array.iter(rows, function (row, index) { Buf.buf_put_string(rpcio, row[0]); Buf.buf_put_int32(rpcio, row[1]); Array.iter(row[2], function (col, index) { DnsInt.buf_put_rights(rpcio, col); }); }); } }); }]); break; case Command.DNS_SETLOOKUP: /* * ------------ * nrows(int16) * [ * dir(capset) * name(string) * ] #nrows * ------------ * [ * status(int16) * cs(capset) * ] #nrows * ------------ */ Io.log((log < 1) || ('Dns_srv_rpc.DNS_SETLOOKUP ' + Net.Print.private(rpcio.header.h_priv))); var nrows = Buf.buf_get_int16(rpcio); var dirs=[]; for(i=0;i