Christiaan den Besten wrote:
Cyrus doesn't support running imapd from the command line. All process are spawned from the master process.

What type of application requires you to run imapd from the command line? I *might* be able to add a command line switch which allows you to do this if its of general use.


We have aprox 300 users who have shell access on the same machine as where the cyrus process runs. It would be -very- nice if they wouldn't have to enter their username/password whenever they run Pine.

Pine supports pre-start commands: "ssh-command=/usr/sbin/imapd" is what we now use with uw-imapd. They can then access their mail folder without having to authenticate themselves.

Attached is a quick proof-of-concept patch against the current CVS (2.2.x) which allows the services to be run outside of master and implements PREAUTH for imapd and allows EXTERNAL to be used for pop3d and nntpd. In order for the services to be run from the command line, they MUST be setuid 'cyrus'.


If people find this useful (I still think this is questionable), I can clean it up and commit it to CVS. I don't know whether the methods I'm using to detect that the process is running outside of master and that the client is connected on stdio are foolproof, but they were quick to implement without too much thought (and didn't require a new command line option).

--
Kenneth Murchison     Oceana Matrix Ltd.
Software Engineer     21 Princeton Place
716-662-8973 x26      Orchard Park, NY 14127
--PGP Public Key--    http://www.oceana.com/~ken/ksm.pgp
? myconfig
? nobody.patch
? preauth.patch
? doc/internal/master-state-machine.png
? imtest/imtest.c.unix_socket
? sieve/foo.bc
? sieve/foo.s
? sieve/ken.bc
? sieve/ken.script
? sieve/test.bc
? sieve/test.msg
? sieve/test.script
Index: imap/imapd.c
===================================================================
RCS file: /afs/andrew/system/cvs/src/cyrus/imap/imapd.c,v
retrieving revision 1.485
diff -u -r1.485 imapd.c
--- imap/imapd.c        16 Sep 2004 17:58:53 -0000      1.485
+++ imap/imapd.c        28 Sep 2004 18:06:51 -0000
@@ -60,6 +60,7 @@
 #include <sys/wait.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
+#include <pwd.h>
 
 #include <sasl/sasl.h>
 
@@ -511,6 +512,35 @@
     imapd_exists = -1;
 }
 
+static void imapd_preauth()
+{
+    uid_t uid = getuid();
+    struct passwd *pw = getpwuid(uid);
+    int r;
+
+    imapd_userid = xstrdup(pw->pw_name);
+    imapd_authstate = auth_newstate(imapd_userid);
+    imapd_userisadmin = global_authisa(imapd_authstate, IMAPOPT_ADMINS);
+
+    syslog(LOG_NOTICE, "login: %s %s preauthenticated",
+          imapd_clienthost, imapd_userid);
+
+    /* Create telemetry log */
+    imapd_logfd = telemetry_log(imapd_userid, imapd_in, imapd_out, 0);
+
+    /* Set namespace */
+    if ((r = mboxname_init_namespace(&imapd_namespace,
+                                    imapd_userisadmin || imapd_userisproxyadmin)) != 
0) {
+       syslog(LOG_ERR, error_message(r));
+       fatal(error_message(r), EC_CONFIG);
+    }
+
+    /* Translate any separators in userid */
+    mboxname_hiersep_tointernal(&imapd_namespace, imapd_userid,
+                               config_virtdomains ?
+                               strcspn(imapd_userid, "@") : 0);
+}
+
 /*
  * run once when process is forked;
  * MUST NOT exit directly; must return with non-zero error code
@@ -644,6 +674,11 @@
            }
        }
     }
+    else if (errno == ENOTSOCK) {
+       /* connected via stdio, preauth as real uid */
+
+       imapd_preauth();
+    }
 
     /* create the SASL connection */
     if (sasl_server_new("imap", config_servername, 
@@ -812,9 +847,16 @@
     char *p, shut[1024];
     const char *err;
 
-    prot_printf(imapd_out,
-               "* OK %s Cyrus IMAP4 %s server ready\r\n", config_servername,
-               CYRUS_VERSION);
+    if (imapd_userid) {
+       prot_printf(imapd_out,
+                   "* PREAUTH %s Cyrus IMAP4 %s server logged in as %s\r\n",
+                   config_servername, CYRUS_VERSION, imapd_userid);
+    }
+    else {
+       prot_printf(imapd_out,
+                   "* OK %s Cyrus IMAP4 %s server ready\r\n",
+                   config_servername, CYRUS_VERSION);
+    }
 
     ret = snprintf(motdfilename, sizeof(motdfilename), "%s/msg/motd",
                   config_dir);
Index: imap/nntpd.c
===================================================================
RCS file: /afs/andrew/system/cvs/src/cyrus/imap/nntpd.c,v
retrieving revision 1.36
diff -u -r1.36 nntpd.c
--- imap/nntpd.c        9 Sep 2004 16:21:26 -0000       1.36
+++ imap/nntpd.c        28 Sep 2004 18:06:51 -0000
@@ -70,6 +70,7 @@
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <ctype.h>
+#include <pwd.h>
 
 #include <sasl/sasl.h>
 #include <sasl/saslutil.h>
@@ -624,6 +625,14 @@
            nntp_haveaddr = 1;
        }
     }
+    else if (errno == ENOTSOCK) {
+       /* connected via stdio, allow external auth as real uid */
+       uid_t uid = getuid();
+       struct passwd *pw = getpwuid(uid);
+
+       saslprops.ssf = 2;
+       saslprops.authid = xstrdup(pw->pw_name);
+    }
 
     /* other params should be filled in */
     if (sasl_server_new("nntp", config_servername, NULL, NULL, NULL,
@@ -633,6 +642,9 @@
     /* will always return something valid */
     secprops = mysasl_secprops(SASL_SEC_NOPLAINTEXT);
     sasl_setprop(nntp_saslconn, SASL_SEC_PROPS, secprops);
+    sasl_setprop(nntp_saslconn, SASL_SSF_EXTERNAL, &saslprops.ssf);
+    if (saslprops.authid)
+       sasl_setprop(nntp_saslconn, SASL_AUTH_EXTERNAL, saslprops.authid);
     
     if(iptostring((struct sockaddr *)&nntp_localaddr, salen,
                  localip, 60) == 0) {
Index: imap/pop3d.c
===================================================================
RCS file: /afs/andrew/system/cvs/src/cyrus/imap/pop3d.c,v
retrieving revision 1.163
diff -u -r1.163 pop3d.c
--- imap/pop3d.c        9 Sep 2004 16:21:26 -0000       1.163
+++ imap/pop3d.c        28 Sep 2004 18:06:51 -0000
@@ -62,6 +62,7 @@
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <ctype.h>
+#include <pwd.h>
 #include "prot.h"
 
 #include <sasl/sasl.h>
@@ -379,6 +380,14 @@
            popd_haveaddr = 1;
        }
     }
+    else if (errno == ENOTSOCK) {
+       /* connected via stdio, allow external auth as real uid */
+       uid_t uid = getuid();
+       struct passwd *pw = getpwuid(uid);
+
+       saslprops.ssf = 2;
+       saslprops.authid = xstrdup(pw->pw_name);
+    }
 
     /* other params should be filled in */
     if (sasl_server_new("pop", config_servername, NULL, NULL, NULL,
@@ -388,6 +397,9 @@
     /* will always return something valid */
     secprops = mysasl_secprops(SASL_SEC_NOPLAINTEXT);
     sasl_setprop(popd_saslconn, SASL_SEC_PROPS, secprops);
+    sasl_setprop(popd_saslconn, SASL_SSF_EXTERNAL, &saslprops.ssf);
+    if (saslprops.authid)
+       sasl_setprop(popd_saslconn, SASL_AUTH_EXTERNAL, saslprops.authid);
     
     if(iptostring((struct sockaddr *)&popd_localaddr,
                  salen, localip, 60) == 0) {
Index: master/service.c
===================================================================
RCS file: /afs/andrew/system/cvs/src/cyrus/master/service.c,v
retrieving revision 1.52
diff -u -r1.52 service.c
--- master/service.c    13 Sep 2004 22:13:04 -0000      1.52
+++ master/service.c    28 Sep 2004 18:06:52 -0000
@@ -338,6 +338,18 @@
     opterr = 1; /* enable error reporting */
     optind = 1; /* reset the option index for parsing by the service */
 
+    if (fstat(LISTEN_FD, &sbuf) == -1 && errno == EBADF) {
+       /* not spawned from master, run as a standalone process */
+
+       cyrus_init(alt_config, argv[0], 0);
+
+       if (service_init(newargc, newargv, envp) != 0) return 1;
+       service_main(newargc, newargv, envp);
+       service_abort(0);
+
+       return 0;
+    }
+
     p = getenv("CYRUS_VERBOSE");
     if (p) verbose = atoi(p) + 1;
 

Reply via email to