~ubuntu-branches/ubuntu/wily/steam/wily

« back to all changes in this revision

Viewing changes to server/net/smtp.pike

  • Committer: Package Import Robot
  • Author(s): Felix Geyer
  • Date: 2013-10-29 19:51:18 UTC
  • mfrom: (1.1.4) (0.1.4 trusty-proposed)
  • Revision ID: package-import@ubuntu.com-20131029195118-b9bxciz5hwx5z459
Tags: 1:1.0.0.39-2ubuntu1
Add an epoch to the version number as there was an unrelated steam package
in the archive with a higher version number.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (C) 2000-2006  Thomas Bopp, Thorsten Hampel, Ludger Merkens
2
 
 * Copyright (C) 2002-2004 Christian Schmidt
3
 
 *
4
 
 *  This program is free software; you can redistribute it and/or modify
5
 
 *  it under the terms of the GNU General Public License as published by
6
 
 *  the Free Software Foundation; either version 2 of the License, or
7
 
 *  (at your option) any later version.
8
 
 *
9
 
 *  This program is distributed in the hope that it will be useful,
10
 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 
 *  GNU General Public License for more details.
13
 
 *
14
 
 *  You should have received a copy of the GNU General Public License
15
 
 *  along with this program; if not, write to the Free Software
16
 
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
 
 * 
18
 
 * $Id: smtp.pike,v 1.5 2006/05/03 11:16:08 exodusd Exp $
19
 
 */
20
 
 
21
 
constant cvs_version="$Id: smtp.pike,v 1.5 2006/05/03 11:16:08 exodusd Exp $";
22
 
 
23
 
/*
24
 
 * implements a smtp-server (see rfc2821 for details)
25
 
 */
26
 
 
27
 
inherit "/net/coal/login";
28
 
inherit "/net/base/line";
29
 
 
30
 
#include <macros.h>
31
 
#include <config.h>
32
 
#include <database.h>
33
 
#include <attributes.h>
34
 
#include <classes.h>
35
 
#include <exception.h>
36
 
#include <access.h>
37
 
 
38
 
#include <mail.h>
39
 
 
40
 
//#define SMTP_DEBUG
41
 
 
42
 
#ifdef SMTP_DEBUG
43
 
#define DEBUG_SMTP(s, args...) werror("net/smtp: "+s+"\n", args)
44
 
#else
45
 
#define DEBUG_SMTP
46
 
#endif
47
 
 
48
 
 
49
 
static int _state = STATE_INITIAL;
50
 
static int _esmtp = 0;
51
 
static string sServer = _Server->query_config("machine");
52
 
static string sDomain = _Server->query_config("domain");
53
 
static string sIP = _Server->query_config("ip");
54
 
static string sFQDN = sServer+"."+sDomain;
55
 
static object oRcpt;
56
 
static object _Forward = _Server->get_module("forward");
57
 
 
58
 
static string sMessage="";
59
 
static string sSender="";
60
 
static array(object) aoRecipients=({});
61
 
 
62
 
//sends a reply to the client, prefixed by a response code
63
 
//if msg is more than one line, each is preceded by this code
64
 
static void send_reply(int code, string msg)
65
 
{
66
 
    array lines = msg / "\n";
67
 
    for(int i=0;i<sizeof(lines); i++)   //multiline reply
68
 
    {
69
 
        if(i==sizeof(lines)-1) send_message(""+code+" "+lines[i]+"\r\n");
70
 
        else send_message(""+code+"-"+lines[i]+"\r\n");
71
 
    }
72
 
}
73
 
 
74
 
//called upon connection, greets the client
75
 
void create(object f)
76
 
{
77
 
    ::create(f);
78
 
 
79
 
    string sTime=ctime(time());
80
 
    sTime=sTime-"\n";   //remove trailing LF
81
 
    oUser = MODULE_USERS->lookup("postman");
82
 
    send_reply(220,sFQDN+" sTeaMail SMTP-Server ver1.0 ready, "+sTime);
83
 
}
84
 
 
85
 
static void ehlo(string client)
86
 
{
87
 
    if(_state!=STATE_INITIAL)
88
 
    {
89
 
        //reset everything important
90
 
        sMessage="";
91
 
        aoRecipients=({});
92
 
    }
93
 
    _esmtp=1;   //client supports ESMTP
94
 
    _state=STATE_IDENTIFIED;    //client identified correctly
95
 
 
96
 
    string addr=query_address();
97
 
    sscanf(addr,"%s %*s",addr); //addr now contains ip of connecting host
98
 
 
99
 
    //verify if given name is correct    
100
 
    object dns = Protocols.DNS.client();
101
 
    array res = dns->gethostbyaddr(addr);
102
 
    if (res[0]==client)    
103
 
        send_reply(250,sServer+" Hello "+client+" ["+addr+"]");
104
 
    else send_reply(250,sServer+" Hello "+client+" ["+addr+"] (Expected \"EHLO "+res[0]+"\")");
105
 
}
106
 
 
107
 
static void helo(string client)
108
 
{
109
 
    if(_state!=STATE_INITIAL)
110
 
    {
111
 
        //reset everything important
112
 
        sMessage="";
113
 
        aoRecipients=({});
114
 
    }
115
 
    _esmtp=0;   //client does not support ESMTP
116
 
    _state=STATE_IDENTIFIED;    //client identified correctly
117
 
 
118
 
    string addr=query_address();
119
 
    sscanf(addr,"%s %*s",addr);
120
 
    
121
 
    //verify if given name is correct    
122
 
    object dns = Protocols.DNS.client();
123
 
    array res = dns->gethostbyaddr(addr);
124
 
    if (res[0]==client)    
125
 
        send_reply(250,sServer+" Hello "+client+" ["+addr+"]");
126
 
    else send_reply(250,sServer+" Hello "+client+" ["+addr+"] (Expected \"HELO "+res[0]+"\")");    
127
 
}
128
 
 
129
 
static void help()
130
 
{
131
 
    send_reply(250,"This is the opensTeam-Mailserver\n"+
132
 
     "Contact: http://www.open-steam.org");
133
 
}
134
 
 
135
 
static int mail(string sender)
136
 
{
137
 
  string localpart, domain;
138
 
  //sender must look like '<sender@domain>'
139
 
  if ( sender == "" || sender == "<>" || 
140
 
      sscanf(sender,"%*s<%s@%s>", localpart, domain) >= 2 ||
141
 
      sscanf(sender, "%s@%s", localpart, domain) == 2 )
142
 
  {
143
 
    sSender=sender;
144
 
    _state=STATE_TRANSACTION;   //waiting for RCPT command(s) now
145
 
    send_reply(250,"Sender accepted"); //NOTE: sender can't be verified
146
 
    return 1;
147
 
  }
148
 
  return 0;
149
 
}
150
 
 
151
 
static array(string) getIPs(string addr)
152
 
{
153
 
  object dns = Protocols.DNS.client();
154
 
 
155
 
  array result = dns->gethostbyname(lower_case(addr));
156
 
  if ( !arrayp(result) || sizeof(result) < 2 )
157
 
    return ({ });
158
 
  
159
 
  return result[1];
160
 
}
161
 
 
162
 
int check_rcpt(string user, string domain)
163
 
{
164
 
  DEBUG_SMTP("Mail to domain=%s - LOCALDOMAIN=%s", domain, sFQDN);
165
 
  
166
 
  int success = 0;
167
 
  if( lower_case(domain) == lower_case(sFQDN) )
168
 
    success = 1;
169
 
  else {   
170
 
    //test if given domain-name matches local ip-adress (->accept it)
171
 
    //workaround for multiple domains on same machine
172
 
    //like "uni-paderborn.de"<->"upb.de"
173
 
    array domains = _Server->query_config("domains");   
174
 
    if ( !arrayp(domains) ) 
175
 
      domains = ({ });
176
 
 
177
 
    domains += ({ _Server->query_config("domain") });
178
 
    if ( search(domains, domain) >= 0 )
179
 
      return 1;
180
 
    
181
 
    array(string) myIPs = getIPs(_Server->get_server_name());
182
 
    array(string) remoteIPs = getIPs(domain);
183
 
    
184
 
    DEBUG_SMTP("Checking IPS: local=%O, remote=%O", myIPs, remoteIPs); 
185
 
    if ( sizeof( (myIPs & remoteIPs) ) > 0 )
186
 
      return 1;
187
 
  }
188
 
  return success;
189
 
}
190
 
 
191
 
static void rcpt(string recipient)
192
 
{
193
 
  string address;
194
 
  if ( sscanf(recipient, "%*s<%s>", address) == 0 )
195
 
    address = recipient;
196
 
  
197
 
  
198
 
  if(lower_case(address)=="postmaster")
199
 
    address="postmaster@"+sFQDN; //rcpt to:<postmaster> is always local!
200
 
  
201
 
  string user, domain;
202
 
  if ( sscanf(address, "%s@%s", user, domain) != 2 ) {
203
 
      FATAL("501 upon smtp: rctp(%O)", recipient);
204
 
    send_reply(501, "syntax error, recipient adress has illegal format");
205
 
    return;
206
 
  }
207
 
 
208
 
  int success = check_rcpt(user, domain);
209
 
 
210
 
  if ( success ) //only accept for local domain
211
 
  {
212
 
      string user = lower_case(user);
213
 
      if(user=="postmaster") user="root";//change to other user,if needed
214
 
      
215
 
      int valid = _Forward->is_valid(user); //check if rcpt is ok
216
 
      DEBUG_SMTP("is_valid() returned "+valid+" for target "+user);
217
 
      if(valid > 0)
218
 
      {
219
 
        aoRecipients+=({user}); //"doubled" recipients will be removed later!
220
 
        send_reply(250,"Recipient ok");
221
 
        _state=STATE_RECIPIENT; //waiting for DATA or RCPT
222
 
      }
223
 
      else if (valid == -1)
224
 
        send_reply(550,"write access failed, set permissions on target first");
225
 
      else if ( valid == 0 ) 
226
 
        send_reply(550,"unknown recipient");
227
 
      else
228
 
        send_reply(450,"unknown error");
229
 
  }
230
 
  else
231
 
    send_reply(550,"we do not relay for you!");
232
 
}
233
 
 
234
 
 
235
 
static void data()
236
 
{
237
 
    //"minimize" list of recipients
238
 
    aoRecipients=Array.uniq(aoRecipients);
239
 
    
240
 
    send_reply(354,"send message now, end with single line containing '.'");
241
 
    _state=STATE_DATA;
242
 
    register_data_func(process_data);
243
 
 
244
 
    //add "received"-Header, see rfc for details
245
 
    string addr=query_address();
246
 
    sscanf(addr,"%s %*s",addr);
247
 
    sMessage="Received: from "+addr+" by "+sFQDN+" "+ctime(time())+
248
 
      "X-Envelope_from: "+sSender +"\n";
249
 
}
250
 
 
251
 
static void process_data(string data)
252
 
{
253
 
    int i;
254
 
    if ( (i=search(data, "\n.\r\n")) > 0 || (i=search(data, "\n.\n")) > 0 ) {
255
 
      data = data[..i];
256
 
    } 
257
 
    else if ( (i=search(sMessage + data, "\n.\r\n")) > 0 ) {
258
 
      sMessage = sMessage[..i];
259
 
      data = "";
260
 
    }
261
 
 
262
 
    if ( i != 0 )
263
 
      sMessage += data;
264
 
 
265
 
    if ( i != -1 )
266
 
    {
267
 
        sMessage+="\r\n";
268
 
        send_reply(250,"Message accepted, size is "+sizeof(sMessage));
269
 
        DEBUG_SMTP("received mail, recipients are:%O",aoRecipients);
270
 
 
271
 
        int res;
272
 
 
273
 
        // make it a task (do not block!)
274
 
        object tmod = get_module("tasks");
275
 
        if ( objectp(tmod) ) {
276
 
          Task.Task rcvTask = Task.Task(_Forward->send_message_raw);
277
 
          rcvTask->params = ({ aoRecipients, sMessage, sSender });
278
 
          tmod->run_task(rcvTask);
279
 
          res = 1;
280
 
        }
281
 
        else
282
 
          res=_Forward->send_message_raw(aoRecipients,sMessage,sSender);
283
 
        DEBUG_SMTP("result of _Forward->send_message_raw(...) is "+res);
284
 
        _state=STATE_IDENTIFIED;
285
 
        unregister_data_func();
286
 
        sMessage="";
287
 
        aoRecipients=({});
288
 
        DEBUG_SMTP("processing data finished !");
289
 
    }
290
 
}
291
 
 
292
 
static void rset()
293
 
{
294
 
    if(_state>STATE_IDENTIFIED) _state=STATE_IDENTIFIED;
295
 
    sMessage="";
296
 
    sSender="";
297
 
    aoRecipients=({});
298
 
    send_reply(250,"RSET completed");
299
 
}
300
 
 
301
 
static void noop()
302
 
{
303
 
    send_reply(250,"NOOP completed");
304
 
}
305
 
 
306
 
static void quit()
307
 
{
308
 
    send_reply(221,""+sServer+" closing connection");
309
 
    _state=STATE_QUIT;
310
 
    close_connection();
311
 
}
312
 
 
313
 
static void vrfy(string user)
314
 
{
315
 
    send_reply(252,"Cannot VRFY user, but will accept message and attempt delivery");
316
 
    //verification code may be added here
317
 
}
318
 
 
319
 
//this function is called for each line the client sends
320
 
static void process_command(string cmd)
321
 
{
322
 
    if(_state==STATE_DATA)
323
 
    {
324
 
        process_data(cmd);
325
 
        return;
326
 
    }
327
 
 
328
 
    string command,params;
329
 
    if(sscanf(cmd,"%s %s",command,params)!=2)
330
 
    {
331
 
        command=cmd;
332
 
        params="";
333
 
    }
334
 
 
335
 
    switch(upper_case(command))
336
 
    {
337
 
        case "EHLO":
338
 
            if(search(params," ")==-1) ehlo(params);
339
 
            else send_reply(501,"wrong number of arguments");
340
 
            break;
341
 
        case "HELO":
342
 
            if(search(params," ")==-1) helo(params);
343
 
            else send_reply(501,"wrong number of arguments");
344
 
            break;
345
 
        case "HELP":
346
 
            help();
347
 
            break;
348
 
        case "MAIL":
349
 
            if(_state==STATE_IDENTIFIED)
350
 
            {
351
 
                array(string) parts=params/":";
352
 
                if(upper_case(parts[0])=="FROM" && sizeof(parts)==2) {
353
 
                  if ( !mail( String.trim_whites(parts[1]) ) ) {
354
 
                    FATAL("501 upon mail, sender illegal path format: %O\n", 
355
 
                          params);
356
 
                    send_reply(501,
357
 
                               "syntax error, return path has illegal format");
358
 
                  }
359
 
                }
360
 
                else 
361
 
                  send_reply(501,"syntax error");
362
 
            }
363
 
            else send_reply(503,"bad sequence of commands - EHLO expected");
364
 
            break;
365
 
        case "RCPT":
366
 
            if(_state==STATE_TRANSACTION||_state==STATE_RECIPIENT)
367
 
            {
368
 
                array(string) parts=params/":";
369
 
                if(upper_case(parts[0])=="TO" && sizeof(parts)==2)
370
 
                    rcpt( String.trim_whites(parts[1]) );
371
 
                else send_reply(501,"syntax error");
372
 
            }
373
 
            else send_reply(503,"bad sequence of commands");
374
 
            break;
375
 
        case "DATA":
376
 
            if(_state==STATE_RECIPIENT)
377
 
            {
378
 
                if (params=="") data();
379
 
                else send_reply(501,"wrong number of arguments");
380
 
            }
381
 
            else send_reply(501,"bad sequence of commands");
382
 
            break;
383
 
        case "RSET":
384
 
            if (params=="") rset();
385
 
            else send_reply(501,"wrong number of arguments");
386
 
            break;
387
 
        case "NOOP":
388
 
            noop();
389
 
            break;
390
 
        case "QUIT":
391
 
            if (params=="") quit();
392
 
            else send_reply(501,"wrong number of arguments");
393
 
            break;
394
 
        case "VRFY":
395
 
            vrfy(params);
396
 
            break;
397
 
        default:
398
 
            send_reply(500,"command not recognized");
399
 
            break;
400
 
    }
401
 
}
402
 
 
403
 
void close_connection()
404
 
{
405
 
    if(_state!=STATE_QUIT) //we got called by idle-timeout
406
 
        send_reply(221,""+sServer+" closing connection, idle for too long");
407
 
    ::close_connection();
408
 
}
409
 
 
410
 
 
411
 
 
412