diff --git a/js/dos/dns_srv_rpc.js b/js/dos/dns_srv_rpc.js new file mode 100644 index 0000000..0722d3e --- /dev/null +++ b/js/dos/dns_srv_rpc.js @@ -0,0 +1,1392 @@ +/** + ** ============================== + ** 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