r278: Set group _after_ setting user, since setting the user may make us lose rights...
[nbd.git] / nbd-server.c
index 26c8f59..4c5792c 100644 (file)
@@ -68,6 +68,7 @@
 #include <sys/mount.h>         /* For BLKGETSIZE */
 #endif
 #include <signal.h>            /* sigaction */
+#include <errno.h>
 #include <netinet/tcp.h>
 #include <netinet/in.h>                /* sockaddr_in, htons, in_addr */
 #include <netdb.h>             /* hostent, gethostby*, getservby* */
@@ -1027,10 +1028,11 @@ int expwrite(off_t a, char *buf, size_t len, CLIENT *client) {
  * @param client The client we're negotiating with.
  **/
 void negotiate(CLIENT *client) {
-       char zeros[300];
+       char zeros[128];
        u64 size_host;
+       u32 flags = NBD_FLAG_HAS_FLAGS;
 
-       memset(zeros, '\0', 290);
+       memset(zeros, '\0', sizeof(zeros));
        if (write(client->net, INIT_PASSWD, 8) < 0)
                err("Negotiation failed: %m");
        cliserv_magic = htonll(cliserv_magic);
@@ -1039,14 +1041,19 @@ void negotiate(CLIENT *client) {
        size_host = htonll((u64)(client->exportsize));
        if (write(client->net, &size_host, 8) < 0)
                err("Negotiation failed: %m");
-       if (write(client->net, zeros, 128) < 0)
+       if (client->server->flags & F_READONLY)
+               flags |= NBD_FLAG_READ_ONLY;
+       flags = htonl(flags);
+       if (write(client->net, &flags, 4) < 0)
+               err("Negotiation failed: %m");
+       if (write(client->net, zeros, 124) < 0)
                err("Negotiation failed: %m");
 }
 
 /** sending macro. */
 #define SEND(net,reply) writeit( net, &reply, sizeof( reply ));
 /** error macro. */
-#define ERROR(client,reply) { reply.error = htonl(-1); SEND(client->net,reply); reply.error = 0; }
+#define ERROR(client,reply,errcode) { reply.error = htonl(errcode); SEND(client->net,reply); reply.error = 0; }
 /**
  * Serve a file to a single client.
  *
@@ -1106,13 +1113,13 @@ int mainloop(CLIENT *client) {
                memcpy(reply.handle, request.handle, sizeof(reply.handle));
                if ((request.from + len) > (OFFT_MAX)) {
                        DEBUG("[Number too large!]");
-                       ERROR(client, reply);
+                       ERROR(client, reply, EINVAL);
                        continue;
                }
 
                if (((ssize_t)((off_t)request.from + len) > client->exportsize)) {
                        DEBUG("[RANGE!]");
-                       ERROR(client, reply);
+                       ERROR(client, reply, EINVAL);
                        continue;
                }
 
@@ -1123,12 +1130,12 @@ int mainloop(CLIENT *client) {
                        if ((client->server->flags & F_READONLY) ||
                            (client->server->flags & F_AUTOREADONLY)) {
                                DEBUG("[WRITE to READONLY!]");
-                               ERROR(client, reply);
+                               ERROR(client, reply, EPERM);
                                continue;
                        }
                        if (expwrite(request.from, buf, len, client)) {
                                DEBUG("Write failed: %m" );
-                               ERROR(client, reply);
+                               ERROR(client, reply, errno);
                                continue;
                        }
                        SEND(client->net, reply);
@@ -1140,7 +1147,7 @@ int mainloop(CLIENT *client) {
                DEBUG("exp->buf, ");
                if (expread(request.from, buf + sizeof(struct nbd_reply), len, client)) {
                        DEBUG("Read failed: %m");
-                       ERROR(client, reply);
+                       ERROR(client, reply, errno);
                        continue;
                }
 
@@ -1543,16 +1550,16 @@ int serveloop(GArray* servers) {
 void dousers(void) {
        struct passwd *pw;
        struct group *gr;
-       if(runuser) {
-               pw=getpwnam(runuser);
-               if(setuid(pw->pw_uid)<0)
-                       msg3(LOG_DEBUG, "Could not set UID: %s", strerror(errno));
-       }
        if(rungroup) {
                gr=getgrnam(rungroup);
                if(setgid(gr->gr_gid)<0)
                        msg3(LOG_DEBUG, "Could not set GID: %s", strerror(errno));
        }
+       if(runuser) {
+               pw=getpwnam(runuser);
+               if(setuid(pw->pw_uid)<0)
+                       msg3(LOG_DEBUG, "Could not set UID: %s", strerror(errno));
+       }
 }
 
 /**