1 # ===================================================================== 2 # putAttachment.awk: RPC I/O function for rpclib/putAttachment. 3 # 4 # Copyright (c) 2007-2012 Carlo Strozzi 5 # 6 # This program is free software; you can redistribute it and/or modify 7 # it under the terms of the GNU General Public License as published by 8 # the Free Software Foundation; version 2 dated June, 1991. 9 # 10 # This program is distributed in the hope that it will be useful, 11 # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 # GNU General Public License for more details. 14 # 15 # You should have received a copy of the GNU General Public License 16 # along with this program; if not, write to the Free Software 17 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 18 # 19 # ===================================================================== 20 21 # ===================================================================== 22 # void _userproc(int mode) 23 # ===================================================================== 24 25 function _userproc(mode, value,a,i,api,mw,tmp) { 26 27 if (mode == _O_REQUEST) { # request. 28 29 nodestem() 30 31 # MetaWeblog API 32 if (_request("0_0",1) ~ /^metaWeblog\./) { 33 api = "mw" 34 bloggerAuth("2_1","3_1","1_1") 35 } 36 37 # target group. 38 value = substr(_request("1",1),1,ENVIRON["TNS_GROUP_MAXLEN"]) 39 40 # MetaWeblog API 41 if (value == _NULL && api == "mw") { 42 split(_request("1_1",1),a,"/") 43 44 # Handle numeric page specification. 45 if (a[2] == _NULL && (a[1]/=1)) { 46 tmp = ENVIRON["CSA_ROOT"] "/var/nodes/" \ 47 substr(a[1],1,1) "/" substr(a[1],2,1) "/" \ 48 substr(a[1],3,1) "/" a[1] 49 50 getline value < tmp; close(tmp) 51 split(value,a,"/") 52 _rcset("cgi.numeric","on") # tell the caller. 53 } 54 55 if (_LANG[a[1]] != _NULL) _rcset("CSA_LANG",a[1]) 56 57 # Target group is expected to be a unixified string here. 58 value = a[2] 59 } 60 61 # group must not be null and it may not contain the 62 # unescaped ``.'' character. 63 64 if (value != _NULL && value !~ /\./) { 65 _rcset("cgi.group",unixify(value)) 66 _rcset("cgi.group.literal",value) 67 } 68 69 # target page within group. 70 value = substr(_request("2",1),1,ENVIRON["TNS_PAGE_MAXLEN"]) 71 72 # page name must be at least 2-character long. 73 if (length(value) > 1) { 74 gsub(/[ \t\n\r]/," ",value) # neutralize real junk. 75 _rcset("cgi.page.literal",value) 76 value = unixify(value,1) 77 _rcset("cgi.page",value) 78 79 # optional attachment short title/description. 80 if ((value=_request("4",1)) != _NULL) { 81 value = substr(value,1,ENVIRON["TNS_ATTACH_MAXDESC"]) 82 gsub(/[\t\r\n]+/," ",value) 83 _rcset("cgi.descr",_strip(value,_O_MIDDLE)) 84 } 85 86 # where to upload this file. 87 # 88 # web: stuff in the public Web area (default) 89 # wiki: stuff in the private Wiki area 90 91 value = _request("6",1) 92 93 # Add more types as needed. Private uploads not available to 94 # the MetaWeblog API (the underlying method defaults to "web"). 95 96 if (api != "mw" && value ~ /^(web|wiki)$/) _rcset("cgi.where",value) 97 98 # Optional attachment author name. If no author was entered 99 # then try and get it from the relevant HTTP cookie, if available. 100 # Unlike page bodies, with attachments the only author recorded 101 # is the one who last uploaded a particular attachment, while 102 # the name of the one who first upload it is not preserved. 103 104 if ((value=_request("5",1)) == _NULL) 105 value = _request("twauthor",1) 106 107 if (value != _NULL) { 108 value = substr(value,1,32) 109 gsub(/[\t\r\n<>]+/," ",value) 110 value = _strip(value,_O_MIDDLE) 111 _rcset("cgi.author",value) 112 } 113 } 114 115 # The attachment file name is a temporary one generated by the 116 # system, but it can theoretically be forced by the client by 117 # using an application/x-www-form-urlencoded MIME type as opposed 118 # to a multipart/form-data one, so a few more sanity checks are 119 # in order. The risk here is that by setting a crafted filename, 120 # the client can fool us into copying a system file of some kind, 121 # say /etc/passwd, as an attachment to the target page or group, 122 # for later download through the attachment management interface of 123 # the application. The _O_ATTACH option tells '_request()' to 124 # guard against this by returning "/dev/null" if appropriate. 125 126 if (api == "mw") { 127 # I only handle the "name" and "bits" elements. 128 for (i=1; (tmp=_request("4_1_" i "_N",1)) != _NULL; i++) { 129 if (tmp == "name") 130 mw["name"] = _strip(_request("4_1_" i,1),_O_CRUSH) 131 else if (tmp == "bits") { 132 mw["bits"] = _request("4_1_" i,1,_O_ATTACH) 133 if (mw["bits"] != "/dev/null") 134 _rcset("cgi.attachment",mw["bits"]) 135 #value = _request("4_1_" i,1,_O_UPNAME) 136 value = mw["name"] 137 } 138 } 139 } 140 else { 141 value = _request("3",1,_O_ATTACH) 142 if (value != "/dev/null") _rcset("cgi.attachment",value) 143 144 # Extract the original filename. 145 value = _request("3",1,_O_UPNAME) 146 } 147 148 # remove leading drive+path info if MSIE. 149 if (ENVIRON["HTTP_USER_AGENT"] ~ / MSIE /) { 150 sub(/.*__/,_NULL,value) 151 sub(/^.*\\/,_NULL,value) # strip up to the rightmost '\' 152 } 153 154 gsub(/[ \t]+/,"_",value) # turn spaces into underscores. 155 156 # filename must contain only allowed characters. 157 158 if (value != _NULL) { 159 160 # This is for compatibility with old page-level 161 # public attachments. 162 gsub(/ /,"+",value) 163 164 # Filename checks need to be relaxed for strongly non-latin 165 # alphabets. 166 #if (value !~ /^[a-zA-Z0-9]+[-_+.a-zA-Z0-9]+[a-zA-Z]$/) 167 if (value !~ /^[^-\/]+[^\/]+[a-zA-Z]+[a-zA-Z0-9]*$/) 168 return(_sys("csaExit.fault 1012")) 169 } 170 171 # For private page attachments try and get target page name 172 # from file name, according to the TW extended syntax 173 # "[pagename+]filename.ext" , where "ext" is one of "jpg", 174 # "pdf", "gif", etc. The page spec, if present, will override 175 # any previous page spec received so far. Only up to the first 176 # embedded "+" in filename will be used as the target page 177 # name, while any other "+" characters will be considered 178 # part of the attachment filename. 179 180 # each of page and file name must be at least 2-character long. 181 if (_request("6",1) == "wiki") { 182 if (split(value,a,"+") && length(a[1]) > 1 && length(a[2]) > 1) { 183 a[1] = substr(a[1],1,ENVIRON["TNS_PAGE_MAXLEN"]) 184 _rcset("cgi.page",unixify(a[1],1)) 185 # I assume the substring up to the first "+" character to 186 # be the embedded page name, so I strip it off to get the 187 # actual attachment file name. 188 sub(/^[^+]+\+/,"",value) 189 190 } 191 192 # Force lower-case extension on any CSV files, in case 193 # they will be used for DBMS purposes. 194 if (sub(/\.[Cc][Ss][Vv]$/,_NULL,value)) value = value ".csv" 195 } 196 197 _rcset("cgi.attname",value) 198 199 # extract file extension, if possible. 200 sub(/.*\./,_NULL,value) 201 value = tolower(value) 202 if (value ~ /^[a-z0-9]+$/) _rcset("cgi.fileext",value) 203 204 # add more types here as needed. 205 if (value ~ /^(web|wiki)$/) _rcset("cgi.where",value) 206 207 # Optional comma- or blank-separated list of authentication 208 # groups who are granted read access to this attachment. 209 # If this is not supplied then the attachment can be read 210 # by anyone. 211 212 value = _request("7",1) 213 gsub(/ +/,",",value); gsub(/,+/,",",value) 214 gsub(/^,+/,"",value); gsub(/,+$/,"",value) 215 216 # remove any duplicated group names in user input. 217 218 if ((i=split(value,a,","))) { 219 value = _NULL 220 _sort(a,i) 221 i = _uniq(a,i) 222 while (i > 0) { 223 if (value == _NULL) value = a[i] 224 else value = value "," a[i] 225 i-- 226 } 227 } 228 229 # Authorization groups are like user IDs: they must always 230 # be lower-case, or things may become messy. 231 value = tolower(value) 232 233 if (value ~ /^([a-z]+[a-z0-9]+,?)+$/) _rcset("cgi.allow",value) 234 235 # The following test is necessary since the address could, 236 # at least in theory, have been set to any string by the 237 # remote user, due to how it is handled to cope with stunnel(8) 238 # and the lack of transproxy support in kernel 2.4.x. 239 240 if (_isipaddr(ENVIRON["REMOTE_ADDR"]) == _TRUE) 241 value = ENVIRON["REMOTE_ADDR"] 242 else value = "0.0.0.0" 243 244 _rcset("REMOTE_ADDR",value) 245 } 246 247 else { # response 248 249 # generic template conditionals. 250 251 ifsections() 252 } 253 } 254 255 # EOF